My question is very similar to those:
However, they don't give the answer to my particular case. Although eventually, I solved the problem but I don't feel this solution to be good and would appreciate if there are better ways to do this. I faced the sort-problem for the first time and would like to understand it better.
From this (modelled) input:
<root>
<measure attribute="attr">
<other n="234">-</other>
<other n="345">-</other>
<element n="2"/>
<element n="1"/>
<element n="3"/>
<other attr="abc">-</other>
</measure>
<measure>
<other n="234">-</other>
<other n="345"><node/></other>
<element n="3"/>
<element n="1"/>
<element n="2"/>
<other attr="abc">-</other>
</measure>
</root>
I want to get this result:
<root>
<measure>
<other n="234">-</other>
<other n="345">-</other>
<element n="1"/>
<element n="2"/>
<element n="3"/>
<other attr="abc">-</other>
</measure>
<measure>
<other n="234">-</other>
<other n="345">
<node/>
</other>
<node/>
<element n="1"/>
<element n="2"/>
<element n="3"/>
<other attr="abc">-</other>
</measure>
</root>
So I want to get particular elements (<element/>
) to be sorted in the relation to each other, but other elements should stay on their positions.
First I tried this: https://xsltfiddle.liberty-development.net/6r5Gh3h/3
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="measure">
<xsl:copy>
<xsl:apply-templates select="@*, node()[local-name()!='element']"/>
<xsl:apply-templates select="element">
<xsl:sort order="ascending" select="@n"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
But it changed the order of the elements.
This solution makes the desired output but are there better ways to do this?
https://xsltfiddle.liberty-development.net/94rmq6j
<xsl:stylesheet exclude-result-prefixes="xs math map array" version="3.0" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="measure">
<xsl:copy>
<xsl:variable name="sortedEls">
<xsl:perform-sort select="child::element">
<xsl:sort data-type="number" order="ascending" select="@n"/>
</xsl:perform-sort>
</xsl:variable>
<xsl:for-each select="descendant::*">
<xsl:choose>
<xsl:when test="local-name() = 'element' and not(following-sibling::element)">
<xsl:sequence select="$sortedEls"/>
</xsl:when>
<xsl:otherwise>
<xsl:if test="local-name() != 'element'">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>