I need an xls version 1 to sort ascending some segments of my document if they contain a value.
<root><!-- some content to not touch --><segment><!-- segment not containing the "field" by which to sort --></segment><segment><field>1</field><!-- some fields to not touch --></segment><segment><field>3</field><!-- some fields to not touch --></segment><segment><field>2</field><!-- some fields to not touch --></segment><segment><!-- segment not containing the "field" by which to sort --></segment></root>
Expected Output
<root><!-- some content to not touch --><segment><!-- segment not containing the "field" by which to sort --></segment><segment><field>1</field><!-- some fields to not touch --></segment><segment><field>2</field><!-- some fields to not touch --></segment><segment><field>3</field><!-- some fields to not touch --></segment><segment><!-- segment not containing the "field" by which to sort --></segment></root>
I'm trying with this xsl but it is not working:
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="xml" indent="yes"/><xsl:template match="/"><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:template><xsl:template match="*"><xsl:choose><xsl:when test="segment"><xsl:copy><xsl:apply-templates select="segment"><xsl:sort select="@field" data-type="number" order="ascending"/></xsl:apply-templates></xsl:copy></xsl:when><xsl:otherwise><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:otherwise></xsl:choose></xsl:template><xsl:template match="@*|node()"><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:template></xsl:stylesheet>
Can anybody help? Thanks
Here is one way you could look at it:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:copy-of select="segment[field][1]/preceding-sibling::node()"/>
<xsl:for-each select="segment[field]">
<xsl:sort select="field"/>
<xsl:copy-of select="."/>
</xsl:for-each>
<xsl:copy-of select="segment[field][last()]/following-sibling::node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
As noted in the comments, this assumes all the segment
elements that have a field
are in a single contiguous block, optionally preceded and/or followed by other nodes.
how to handle non-contiguous elements? In this case, sorting each block separately?
i can use v.2.0
You could do:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:for-each-group select="segment" group-adjacent="boolean(field)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:perform-sort select="current-group()">
<xsl:sort select="field"/>
</xsl:perform-sort>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>