I want to sort all the <text>
elements by the value of the attribute top
.
However an element should only be sorted if its previous sibling has a value of top
that exceeds its own by 2 or more units.
For example, the following elements
<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>
<text top="35">text 5</text>
<text top="40">text 6</text>
should be transformed to:
<text top="35">text 5</text>
<text top="40">text 6</text>
<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>
So that the group:
<text top="100">text 1</text>
<text top="99">text 2</text>
<text top="100">text 3</text>
<text top="99">text 4</text>
remains as is after sorting.
I only use XSLT from time to time and only know the usual sorting approach:
<xsl:for-each select="text">
<xsl:sort select="@top" />
<xsl:copy>
<xsl:copy-of select="./node()|./@*" />
</xsl:copy>
</xsl:for-each>
But the result I want to achieve would require some kind of bubble sort.
Not sure whether it's doable with pure XSLT. I have an XSLT 2.0 processor.
I wonder whether in XSLT 2/3 it can just be done with an adequate group-ending-with
pattern:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="limit" as="xs:integer" select="1"/>
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="root">
<xsl:for-each-group select="text" group-ending-with="text[abs(xs:decimal(following-sibling::text[1]/@top) - xs:decimal(@top)) > $limit]">
<xsl:sort select="min(current-group()/@top/xs:decimal(.))"/>
<xsl:sequence select="current-group()"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Based on the much simplified XQuery code
for tumbling window $group in root/text
start when true()
end $e next $ne when abs(xs:decimal($ne/@top) - xs:decimal($e/@top)) > 1
order by min($group/@top/xs:decimal(.))
return
$group