Это преобразование точно соответствует заявленным требованиям. Особое внимание уделяется сохранению точного порядка элементов, которые не нужно сортировать. Никакой другой ответ в настоящее время не делает это :
<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:param name="vField" select="'field1'"/>
<xsl:param name="pSortType" select="'number'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(name(),'Data')]">
<xsl:variable name="vPos" select=
"count(preceding-sibling::*[starts-with(name(),'Data')])+1"/>
<xsl:for-each select="/*/*[starts-with(name(),'Data')]">
<xsl:sort select="Values[Name=$vField]/Value"
data-type="{$pSortType}"/>
<xsl:if test="position() = $vPos">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
При применении к следующему XML-документу (аналогично предоставленному документу, но с дополнительным <Element C=""/>
, вставленным между Data1
и Data2
, чтобы мы могли проверить сохранение порядка несортированные элементы):
<Root>
<Element A=""/>
<Element B=""/>
<Data1>
<DataElement/>
<Values>
<Value>2222</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>ABC</Value>
<Name>field2</Name>
</Values>
</Data1>
<Element C=""/>
<Data2>
<DataElement/>
<Values>
<Value>1111</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>XYZ</Value>
<Name>field2</Name>
</Values>
</Data2>
</Root>
дает желаемый, правильный результат - обратите внимание, что позиция <Element C=""/>
сохраняется :
<Root>
<Element A=""/>
<Element B=""/>
<Data2>
<DataElement/>
<Values>
<Value>1111</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>XYZ</Value>
<Name>field2</Name>
</Values>
</Data2>
<Element C=""/>
<Data1>
<DataElement/>
<Values>
<Value>2222</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>ABC</Value>
<Name>field2</Name>
</Values>
</Data1>
</Root>