xml - How can I use XSLT to permutate a node hierarchy, part 2 -
this question extends previous question.
in previous question asked how permutate node hierarchy in tree of fixed depth. example every leaf path /x/y/z wanted leaf in output have path y/x/z. (permutation 2,1,3).
instead of handling fixed-length permutations, want permutations "2,1, 3..n-1"
so xslt looks this:
<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="/input"> <output> <xsl:apply-templates select="text()"/> </output> </xsl:template> <!-- example 2,1,3:n --> <xsl:template match="text()"> <xsl:variable name="n" select="5" /> <!-- should later depth of leaf --> <xsl:element name="{name(ancestor::*[2])}"> <!-- 2 --> <xsl:element name="{name(ancestor::*[1])}"> <!-- 1 --> <xsl:call-template name="loop"> <!-- 3:5 --> <xsl:with-param name="i" select="3" /> <xsl:with-param name="end" select="$n - 1" /> </xsl:call-template> </xsl:element> </xsl:element> </xsl:template> <xsl:template name="loop"> <xsl:param name="i" /> <xsl:param name="end" /> <xsl:choose> <xsl:when test="$i = $end"> <xsl:copy-of select="."/> </xsl:when> <xsl:otherwise> <xsl:element name="{name(ancestor::*[$i])}"> <!-- recursive call --> <xsl:call-template name="loop"> <xsl:with-param name="i" select="$i+1" /> <xsl:with-param name="end" select="$end" /> </xsl:call-template> </xsl:element> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
i'm not sure if recursive use of templates work theoretically. on right track?
i believe generic solution this:
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="/*"> <output> <xsl:apply-templates select="//text()"/> </output> </xsl:template> <xsl:template match="text()"> <xsl:call-template name="re-order"> <xsl:with-param name="node-set" select="ancestor::*|." /> <xsl:with-param name="order">2,1,3,</xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template name="re-order"> <xsl:param name="node-set" /> <xsl:param name="order" /> <xsl:param name="i" select="1" /> <xsl:variable name="n" select="count($node-set)" /> <xsl:variable name="p"> <xsl:choose> <xsl:when test="$order"> <xsl:value-of select="substring-before($order, ',')" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="$i" /> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="$i < $n"> <xsl:element name="{name($node-set[number($p)])}"> <!-- recursive call --> <xsl:call-template name="re-order"> <xsl:with-param name="node-set" select="$node-set" /> <xsl:with-param name="order" select="substring-after($order, ',')" /> <xsl:with-param name="i" select="$i + 1" /> </xsl:call-template> </xsl:element> </xsl:when> <xsl:otherwise> <xsl:copy-of select="$node-set[last()]"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
test input:
<one> <two> <three>3.1</three> <three>3.2</three> </two> <two> <three> <four>4.1</four> <four>4.2</four> </three> <three> <four> <five>5.1</five> <five>5.2</five> </four> <four> <five>5.3</five> <five>5.4</five> </four> </three> </two> <two> <three> <four> <five> <six>6.1</six> <six>6.2</six> </five> </four> </three> </two> <two>2.1</two> <two>2.2</two> </one>
result:
<?xml version="1.0" encoding="utf-8"?> <output> <two> <one> <three>3.1</three> </one> </two> <two> <one> <three>3.2</three> </one> </two> <two> <one> <three> <four>4.1</four> </three> </one> </two> <two> <one> <three> <four>4.2</four> </three> </one> </two> <two> <one> <three> <four> <five>5.1</five> </four> </three> </one> </two> <two> <one> <three> <four> <five>5.2</five> </four> </three> </one> </two> <two> <one> <three> <four> <five>5.3</five> </four> </three> </one> </two> <two> <one> <three> <four> <five>5.4</five> </four> </three> </one> </two> <two> <one> <three> <four> <five> <six>6.1</six> </five> </four> </three> </one> </two> <two> <one> <three> <four> <five> <six>6.2</six> </five> </four> </three> </one> </two> <two> <one>2.1</one> </two> <two> <one>2.2</one> </two> </output>
notes:
- by default, root element included top-most ancestor of leaf text node (you can override when calling template fist time);
- it assumed depth of leaf text node no less number of tokens in
$order
parameter; otherwise may unexpected results.
Comments
Post a Comment