This transformation seems to be the most efficient of the currently posted solutions -- no count(preceding-sibling::*)
, and no //content[@key=$key]
-- both of which result in O(N^2) -- quadratical time complexity:
<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:key name="kContByAtttr" match="content" use="@key"/>
<xsl:key name="kVidByAtttr" match="video" use="@key"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="contents">
<contents>
<xsl:for-each select="/*/videos/video">
<xsl:apply-templates select="key('kContByAtttr', @key)"/>
</xsl:for-each>
<xsl:apply-templates select="*[not(key('kVidByAtttr', @key))]"/>
</contents>
</xsl:template>
</xsl:stylesheet>
When applied on the provided XML (wrapped into a single top element to become a) document:
<t>
<videos>
<video key="13" />
<video key="41" />
<video key="61" />
</videos>
<contents>
<content key="61" />
<content key="41" />
<content key="13" />
<content key="10" />
</contents>
</t>
produces the wanted, correct result:
<t>
<videos>
<video key="13"/>
<video key="41"/>
<video key="61"/>
</videos>
<contents>
<content key="13"/>
<content key="41"/>
<content key="61"/>
<content key="10"/>
</contents>
</t>