Сопоставьте элемент с динамическим значением атрибута

Я пытаюсь прототипировать преобразование, чтобы превратить xsl:schema в php-интерфейс. У меня небольшая проблема, xsd:simpleType элементами xsd:simpleType которые имеют атрибут name соответствующий атрибуту type элементов xsd:element . Предположим, у меня есть такая схема:

 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="Foo" type="Bar"/> <xsd:simpleType name="Bar"> <xsd:restriction base="xsd:string"> <xsd:maxLength value="32"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> 

Я хотел бы получить следующий результат.

 <?php interface Foo { public abstract function buildFooXmlString(Bar $a); } 

Вот xslt, который у меня есть до сих пор:

 <xsl:stylesheet version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="*"/> <xsl:template match="/">&lt;?php <xsl:apply-templates select="xsd:schema"/></xsl:template> <xsl:template match="xsd:schema">interface FromXsd { <xsl:apply-templates select="xsd:element"/> }</xsl:template> <xsl:template match="xsd:element"> <xsl:apply-templates select="xsd:annotation"/> abstract public function build<xsl:value-of select="normalize-space(@name)"/>XmlString(<xsl:apply-templates select="@type"/>); </xsl:template> <xsl:template match="xsd:annotation">/* <xsl:value-of select="normalize-space()"/> */</xsl:template> <xsl:template match="@type"><xsl:apply-templates select="//xsd:simpleType[@name=normalize-space()]"/></xsl:template> <xsl:template match="xsd:simpleType"><xsl:value-of select="local-name()"/> $a</xsl:template> </xsl:stylesheet> 

Он производит большую часть желаемого результата, но не содержит ничего внутри круглых скобок:

 <?php interface Foo { public abstract function buildFooXmlString(); } 

Как я могу выбрать узел simpleType с атрибутом name соответствующим type element ? (Имена должны быть уникальными для типов xsd.)

Узел simpleType никогда не выбирается, потому что в шаблоне, где вы сопоставляете xsd:schema , вы применяете только шаблоны к дочернему поддереву xsd:element . xsd:simpleType sibling никогда не будет обработан.

Если вы хотите разрешить обработку всех дочерних узлов узла, вы должны включить пустой <xsl:apply-templates/> внутри шаблона xsd:schema .

Это все равно не приведет к желаемому результату. На самом деле это намного проще. Чтобы генерировать фрагмент кода, который вы ожидаете, вам не нужно читать элемент xsd:simpleType , так как атрибут, который содержит xsd:simpleType вам тип, может быть непосредственно получен из атрибута @type элемента xsd:element с использованием xsd:value-of , и вы можете просто напечатать $a сразу после него:

 XmlString(<xsl:value-of select="@type"/> $a) 

Поскольку вы генерируете текст, вы должны использовать элементы <xsl:text> для управления распределением пробелов. Например, если вы используете:

 <xsl:template match="/"> <xsl:text>&lt;?php </xsl:text> <xsl:apply-templates select="xsd:schema"/> </xsl:template> 

Вам не нужно беспокоиться о том, чтобы всегда помещать текст &lt;?php сразу после <xsl:template> и может обычно отступать от кода. Вы также можете включить новые строки с помощью &#xa; символ (и он не нарушит ваше форматирование):

 <xsl:template match="xsd:schema"> <xsl:text>interface FromXsd {&#xa;</xsl:text> <xsl:apply-templates select="xsd:element"/><xsl:text>&#xa;</xsl:text> <xsl:apply-templates select="xsd:annotation"/> <xsl:text>&#xa;}</xsl:text> </xsl:template> 

Я отредактировал ваш XSL и внесли эти изменения в документ XSL ниже:

 <xsl:stylesheet version="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="*"/> <xsl:template match="/"> <xsl:text>&lt;?php </xsl:text> <xsl:apply-templates select="xsd:schema"/> </xsl:template> <xsl:template match="xsd:schema"> <xsl:text>interface FromXsd {&#xa;</xsl:text> <xsl:apply-templates select="xsd:element"/><xsl:text>&#xa;</xsl:text> <xsl:apply-templates select="xsd:annotation"/> <xsl:text>&#xa;}</xsl:text> </xsl:template> <xsl:template match="xsd:element"> <xsl:apply-templates select="xsd:annotation"/> <xsl:text> abstract public function build</xsl:text> <xsl:value-of select="normalize-space(@name)"/> <xsl:text>XmlString(</xsl:text> <xsl:value-of select="@type"/><xsl:text> $a</xsl:text> <xsl:text>);</xsl:text> </xsl:template> <xsl:template match="xsd:annotation"> <xsl:text> /* </xsl:text> <xsl:value-of select="normalize-space(.)"/> <xsl:text> */</xsl:text> </xsl:template> </xsl:stylesheet> 

Если у вас есть вход, такой как:

 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="Foo" type="Bar"/> <xsd:simpleType name="Bar"> <xsd:restriction base="xsd:string"> <xsd:maxLength value="32"/> </xsd:restriction> </xsd:simpleType> <xsd:annotation> <xsd:documentation>This is a comment</xsd:documentation> </xsd:annotation> </xsd:schema> 

Он даст результат ниже:

 <?php interface FromXsd { abstract public function buildFooXmlString(Bar $a); /* This is a comment */ }