Порядок получения требуемого результата может быть легко определен с помощью <xsl:sort>
:
Это естественно и просто и практически не требует взломов.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vOrder" select=
"2*boolean(/*/Option[1]/@name)-1"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each select="Option">
<xsl:sort data-type="number" select="$vOrder* position()"/>
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование выполняется для этого XML-документа :
<OptionList>
<Option name="My First Option" />
<Option name="My Second Option" />
<Option name="My Third Option" />
</OptionList>
, будет получен требуемый, правильный результат :
<OptionList>
<Option name="My First Option"/>
<Option name="My Second Option"/>
<Option name="My Third Option"/>
</OptionList>
Когда то же самое преобразование теперь выполняется для этого XML-документа :
<OptionList>
<Option />
<Option name="My Second Option" />
<Option name="My Third Option" />
</OptionList>
требуемый, правильный результат получается снова :
<OptionList>
<Option name="My Third Option"/>
<Option name="My Second Option"/>
<Option/>
</OptionList>
Объяснение : переменная $vOrder
определена таким образом, что она равна -1
, если первый элемент Option
не имеет атрибута name
и равен +1
, если первый *Элемент 1036 * имеет атрибут name
.Здесь мы используем тот факт, что false()
автоматически преобразуется в 0
и true()
в 1
.
Мы также используем тот факт, что когда знак каждого числа в последовательности возрастающих положительных чисел (позиции), порядок новой последовательности уменьшается.