I am having trouble implementing a sort. I have an XML document that I want to do a 1 for 1 copy except sort certain elements into order. The structure of the document must be the same after the copy in order to validate against the schema. I am not in control of the schema so I cannot modify it. Here is a simplified version of my XML data:
<ResponseDoc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<resHead>
<id>R1983Rs</id>
</resHead>
<item>
<objRef>
<objId>100</objId>
<sysId>xyz</sysId>
</objRef>
<!-- Additional data here -->
</item>
<item>
<objRef>
<objId>140</objId>
<sysId>abc</sysId>
</objRef>
<!-- Additional data here -->
</item>
<resFoot>
<id>1234</id>
</resFoot>
</ResponseDoc>
I want to sort the <item>
elements into a specific order. The resulting XML file should be:
<ResponseDoc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<resHead>
<id>R1983Rs</id>
</resHead>
<item>
<objRef>
<objId>140</objId>
<sysId>abc</sysId>
</objRef>
<!-- Additional data here -->
</item>
<item>
<objRef>
<objId>100</objId>
<sysId>xyz</sysId>
</objRef>
<!-- Additional data here -->
</item>
<resFoot>
<id>1234</id>
</resFoot>
</ResponseDoc>
I was successful in sorting with the following XSL stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:template match="ResponseDoc">
<xsl:copy>
<xsl:apply-templates select="resHead" />
<xsl:apply-templates select="item">
<xsl:sort select="number(objRef/objId)" order="descending" />
</xsl:apply-templates>
<xsl:apply-templates select="resFoot" />
</xsl:copy>
</xsl:template>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
But this is unsatisfying since I need to explicitly handle <resHead>
and <resFoot>
and if the schema is expanded to include additional sibling(s) to <item>
, I will need to search out this XSL and modify it. I have done a great deal of research but only find examples that either don't i开发者_运维百科nclude any sibling elements OR contain the "sorted" elements within some "container" element, i.e.:
...
<items>
<item>...</item>
<item>...</item>
<item>...</item>
</items>
...
I'd like to find more generic way of accomplishing the sort. I've attempted many varients of the working style sheet but I either lose or reposition the sibling nodes or break the sort. Can anyone help out?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/">
<xsl:for-each select="ResponseDoc">
<xsl:sort select="item" order="descending" />
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here's a solution that will work if all your item
elements are contiguous:
<xsl:template match="ResponseDoc">
<xsl:copy>
<xsl:apply-templates select="item[1]/preceding-sibling::*" />
<xsl:apply-templates select="item">
<xsl:sort select="number(objRef/objId)" order="descending" />
</xsl:apply-templates>
<xsl:apply-templates select="item[last()]/following-sibling::*" />
</xsl:copy>
</xsl:template>
It simply species any siblings that come before the first item
element instead of resHead
, and any siblings that come after the last item
element instead of resFoot
.
精彩评论