Reputation: 43
I have an xml sheet of this kind:
<houses>
<house number="1">
<mainroom>
<roomprice>5</roomprice>
<roomtax>2</roomtax>
</mainroom>
<roompricefull>
<price value="8"/>
</roompricefull>
</house>
<house number="2">
<mainroom>
<roomprice>3</roomprice>
<roomtax>1</roomtax>
</mainroom>
<roompricefull>
<price value="7"/>
</roompricefull>
</house>
<house number="3">
<mainroom>
<roomprice>9</roomprice>
<roomtax>1</roomtax>
</mainroom>
<roompricefull>
<price value="4"/>
</roompricefull>
</house>
<house number="4">
<mainroom>
<roomprice>12</roomprice>
<roomtax>3</roomtax>
</mainroom>
<roompricefull>
<price value="6"/>
</roompricefull>
</house>
</houses>
so I had to change the value of attribute "value" in "price" element in each of the "house" with the sum of "roomprice" value and "roomtax"
I wrote an xsl transformation of such a kind:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="PriceChange" match="price[parent::roompricefull]">
<xsl:copy>
<xsl:variable name="sn" select="../../@number"/>
<xsl:variable name="TaxValue" select="number(//house[@number=string($sn)]/mainroom/roomtax)"/>
<xsl:variable name="BaseValue" select="number(//house[@number=string($sn)]/mainroom/roomprice)"/>
<xsl:attribute name="value">
<xsl:value-of select="string($TaxValue+$BaseValue)"/>
</xsl:attribute>
<!--xsl:for-each select="/houses/house">
<xsl:sort select="houses/house[$sn]/roompricefull/@value"/>
</xsl:for-each-->
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
But when I started working on sorting "house" elements by my new value, I found problems. I actually don't understand why it's not working, so I commented my last of the dozens examples in up code.
I got this:
<houses>
<house number="1">
<mainroom>
<roomprice>5</roomprice>
<roomtax>2</roomtax>
</mainroom>
<roompricefull>
<price value="7"/>
</roompricefull>
</house>
<house number="2">
<mainroom>
<roomprice>3</roomprice>
<roomtax>1</roomtax>
</mainroom>
<roompricefull>
<price value="4"/>
</roompricefull>
</house>
<house number="3">
<mainroom>
<roomprice>9</roomprice>
<roomtax>1</roomtax>
</mainroom>
<roompricefull>
<price value="10"/>
</roompricefull>
</house>
<house number="4">
<mainroom>
<roomprice>12</roomprice>
<roomtax>3</roomtax>
</mainroom>
<roompricefull>
<price value="15"/>
</roompricefull>
</house>
</houses>
But the expected result was:
<houses>
<house number="4">
<mainroom>
<roomprice>12</roomprice>
<roomtax>3</roomtax>
</mainroom>
<roompricefull>
<price value="15"/>
</roompricefull>
</house>
<house number="3">
<mainroom>
<roomprice>9</roomprice>
<roomtax>1</roomtax>
</mainroom>
<roompricefull>
<price value="10"/>
</roompricefull>
</house>
<house number="1">
<mainroom>
<roomprice>5</roomprice>
<roomtax>2</roomtax>
</mainroom>
<roompricefull>
<price value="7"/>
</roompricefull>
</house>
<house number="2">
<mainroom>
<roomprice>3</roomprice>
<roomtax>1</roomtax>
</mainroom>
<roompricefull>
<price value="4"/>
</roompricefull>
</house>
</houses>
It would be great if you could help me with sorting and explaining why my example is not working. Seems that I don't understand the meaning of <sort/>, but everything I find tells me just about the usage of it without any explanation. Thank you in advance.
Upvotes: 3
Views: 825
Reputation: 24826
it would be great if you could help me with sorting
This is the correct XSLT 1.0 approach.
Notice the correct use of xsl:sort
which needs:
xsl:apply-templates
the sorting order also to be specified being the default ascending
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="houses">
<xsl:copy>
<xsl:apply-templates select="house">
<xsl:sort select="mainroom/roomprice + mainroom/roomtax"
data-type="number"
order="descending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="price/@value">
<xsl:value-of select="
../../../mainroom/roomprice
+
../../../mainroom/roomtax"/>
</xsl:template>
explaining why my example is not working
Your transform does no work mainly because you are trying to sort elements in the wrong context (inside a template matching a deep child in the tree). Moreover:
xsl:sort
attributesUpvotes: 4
Reputation: 7184
Sort by the new price:
<xsl:template match="/">
<xsl:for-each select="house">
<xsl:sort select="mainroom/roomprice + mainroom/roomtax"/>
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
As before:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
Adjust the price in the output:
<xsl:template match="roompricefull">
<roompricefull>
<price value="{../mainroom/roomprice + ../mainroom/roomtax}"/>
</roompricefull>
</xsl:template>
Upvotes: 0