Sojimanatsu
Sojimanatsu

Reputation: 601

How to re-order the nodes including child nodes in XSLT 2.0

I have been trying to change the order of the nodes based on structure.

Lets assume that we have an example xml

<?xml version="1.0" encoding="UTF-8"?>
<ParentNode>
  <example>value</example>
  <example>value</example>
  <node>
     <one>1</one>
     <two>1</two>
     <three>1</three>
     <four>1</four>
  </node>
  <node>
     <one>2</one>
     <two>2</two>
     <three>2</three>
     <four>2</four>
  </node>
</ParentNode>

This <node> part is repeating for other values as well, this is the simplified version of the whole structure.

What i want is: I want to change the order of the <node> with values 2 , with <node> with values 1

 <?xml version="1.0" encoding="UTF-8"?>
<ParentNode>
  <example>value</example>
  <example>value</example>
  <node>
     <one>2</one>
     <two>2</two>
     <three>2</three>
     <four>2</four>
  </node>
  <node>
     <one>1</one>
     <two>1</two>
     <three>1</three>
     <four>1</four>
  </node>
</ParentNode>

Lets assume that, <three> is a key value for us to re-order the nodes, So i would like to say <xsl:when test="value=2"> put whole before the first one.

How can i write it in XSLT 2.0 ?

EDIT: I found the solution by changing the variables inside the templates, So What i did is, putting the value "2" nodes into "1" and, This is a manual solution, but at the end, it works. Thank you for the ideas

Upvotes: 0

Views: 259

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167516

Write two templates

  <xsl:template match="node[three = 1]">
      <xsl:copy-of select="../node[three = 2]"/>
  </xsl:template>

  <xsl:template match="node[three = 2]">
      <xsl:copy-of select="../node[three = 1]"/>
  </xsl:template>

plus the identity transformation and the two elements are swapped (XSLT 3 version at http://xsltfiddle.liberty-development.net/3Nqn5Yd, for XSLT 2 you have to spell out the identity transformation template:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

  <xsl:template match="node[three = 1]">
      <xsl:copy-of select="../node[three = 2]"/>
  </xsl:template>

  <xsl:template match="node[three = 2]">
      <xsl:copy-of select="../node[three = 1]"/>
  </xsl:template>

</xsl:transform>

http://xsltransform.hikmatu.com/gWcDMek

Upvotes: 2

zx485
zx485

Reputation: 29022

If you happen to have any literal order in your nodes values you could use the xsl:sort function to reorder your them:

<xsl:template match="/ParentNode">
  <xsl:copy>
    <xsl:copy-of select="example" />
    <xsl:for-each select="node">  
      <xsl:sort select="three" order="descending" />
      <xsl:copy>
        <xsl:copy-of select="node()|@*" />
      </xsl:copy>
    </xsl:for-each>
  </xsl:copy>
</xsl:template>

Output:

<ParentNode>
    <example>value</example>
    <example>value</example>
    <node>
        <one>2</one>
        <two>2</two>
        <three>2</three>
        <four>2</four>
    </node>
    <node>
        <one>1</one>
        <two>1</two>
        <three>1</three>
        <four>1</four>
    </node>
</ParentNode>

Upvotes: 1

Related Questions