Reputation: 67
I have been working over a requirement where I need to sort a part of the xml document (not the complete tree).
<Root>
<AllData>
<Data_not_to_be_sorted>
<Additional_data1>
<Some_test_data1/>
<Some_test_data2/>
</Additional_data1>
</Data_not_to_be_sorted>
<RealData>
<Some_data1/>
<Some_data2/>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>4</Value>
<Name>name in 4</Name>
</Father>
</GrandFather>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>3</Value>
<Name>name in 3</Name>
</Father>
</GrandFather>
</RealData>
<RealData>
<Some_data1/>
<Some_data2/>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>2</Value>
<Name>name in 2</Name>
</Father>
</GrandFather>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>1</Value>
<Name>name in 1</Name>
</Father>
</GrandFather>
</RealData>
</AllData>
</Root>
So after sorting on Father/Value, I should be getting correct sequence of GrandFather
<Root>
<AllData>
<Data_not_to_be_sorted>
<Additional_data1>
<Some_test_data1/>
<Some_test_data2/>
</Additional_data1>
</Data_not_to_be_sorted>
<RealData>
<Some_data1/>
<Some_data2/>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>3</Value>
<Name>name in 3</Name>
</Father>
</GrandFather>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>4</Value>
<Name>name in 4</Name>
</Father>
</GrandFather>
</RealData>
<RealData>
<Some_data1/>
<Some_data2/>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>1</Value>
<Name>name in 1</Name>
</Father>
</GrandFather>
<GrandFather>
<Data_required_as_it_is></Data_required_as_it_is>
<Father>
<Value>2</Value>
<Name>name in 2</Name>
</Father>
</GrandFather>
</RealData>
</AllData>
</Root>
In other words, I want to sort over sub tree GrandFather based on Father/Value. Rest everything should remain same. I have tried something like below ..but this is just copying the source xml into output.
<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="*"/>
<!-- Template to copy the nodes as they are -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GrandFather">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()">
<xsl:sort select="self::Father/Value" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Views: 637
Reputation: 243449
This correct, shorter, simpler and more general transformation:
<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:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[F]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()">
<xsl:sort select="self::F/Value" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied to the provided XML document:
<Root>
<AllData>
<Data_not_to_be_sorted>
<Additional_data1>
<Some_test_data1/>
<Some_test_data2/>
</Additional_data1>
</Data_not_to_be_sorted>
<data>
<Some_data1></Some_data1>
<Some_data2></Some_data2>
<F>
<Value>2</Value>
<Name>name in 2</Name>
</F>
<F>
<Value>1</Value>
<Name>name in 1</Name>
</F>
</data>
<data>
<Some_data1></Some_data1>
<Some_data2></Some_data2>
<F>
<Value>4</Value>
<Name>name 4</Name>
</F>
<F>
<Value>3</Value>
<Name>name in 3</Name>
</F>
</data>
</AllData>
</Root>
produces the wanted, correct result:
<Root>
<AllData>
<Data_not_to_be_sorted>
<Additional_data1>
<Some_test_data1/>
<Some_test_data2/>
</Additional_data1>
</Data_not_to_be_sorted>
<data>
<Some_data1/>
<Some_data2/>
<F>
<Value>1</Value>
<Name>name in 1</Name>
</F>
<F>
<Value>2</Value>
<Name>name in 2</Name>
</F>
</data>
<data>
<Some_data1/>
<Some_data2/>
<F>
<Value>3</Value>
<Name>name in 3</Name>
</F>
<F>
<Value>4</Value>
<Name>name 4</Name>
</F>
</data>
</AllData>
</Root>
Upvotes: 2
Reputation: 86774
The problem is that F/Value
is not a child of Root
. Also, applying a sort just under Root
(if you provided a usable sort key) would sort just the child elements of the root. You will need to do something like this (untested):
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<xsl:apply-templates select="Some_data1"/>
<xsl:apply-templates select="Some_data2"/>
<xsl:apply-templates select="F">
<xsl:sort select="Value"/>
</xsl:apply-templates>
</xsl:template>
The key is to remember that the stylesheet is declarative, not procedural. The XSLT engine reads your XML, and at each input element it looks at the stylesheet to decide what to output.
Upvotes: 0