I have a following XML
I think you can go with this simple transform:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="field" select="'field1'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Root">
<xsl:copy>
<xsl:apply-templates select="@*|*">
<xsl:sort select="Values[Name=$field]/
Value[string(number(.))!='NaN']"
data-type="number"/>
<xsl:sort select="Values[Name=$field]/
Value[string(number(.))='NaN']"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your input (corrected to make it well-formed):
<Root>
<Element A=""/>
<Element B=""/>
<Data1>
<DataElement/>
<Values>
<Value>2222</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>ABC</Value>
<Name>field2</Name>
</Values>
</Data1>
<Data2>
<DataElement/>
<Values>
<Value>1111</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>XYZ</Value>
<Name>field2</Name>
</Values>
</Data2>
</Root>
produces:
<Root>
<Element A=""></Element>
<Element B=""></Element>
<Data2>
<DataElement></DataElement>
<Values>
<Value>1111</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>XYZ</Value>
<Name>field2</Name>
</Values>
</Data2>
<Data1>
<DataElement></DataElement>
<Values>
<Value>2222</Value>
<Name>field1</Name>
</Values>
<Values>
<Value>ABC</Value>
<Name>field2</Name>
</Values>
</Data1>
</Root>
Explanation:
This transformation implements exactly the stated requirements. It takes special care to preserve the exact order of the elements that are not to be sorted. No other answer at present does this:
<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>
When applied on the following XML document (the same as the provided one, but with an additional <Element C=""/>
inserted between Data1
and Data2
so that we can verify the preservation of ordering of the non-sorted elements):
<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>
produces the wanted, correct result -- note that the position of <Element C=""/>
is preserved:
<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>