I am very new to xslt, and found it can be easy or complex.
I want to make clear some concepts.
What is preceding-sibling and what is ancestor, after searching from google, I found ancestor explanation. and the chart from their website makes easier to understand.
But I still don't understand preceding-sibling
<product>
<inventory>
<drink>
<lemonade>
<price>$2.50</price>
<amount>20</amount>
</lemonade>
<pop>
<price>$1.50</price>
<amount>10</amount>
</pop>
</drink>
<service>
<address />
<phone />
<delivery> City </delivery>
</service>
<snack>
<chips>
<price>$4.50</price>
<amount>60</amount>
</chips>
</snack>
<hotfood></hotfood>
<totalprice> $15</totleprice>
</inventory>
</product>
so how do I read this preceding-sibling::pop/ancestor::inventory/totalprice
ancestor::inventory/totalprice = product\inventory\totalprice
preceding-sibling::pop - I dont understand this one
then how to read all together?
Many thanks
The preceding-sibling:: axis
The preceding-sibling:: axis is an axis of navigation that includes all the preceding sibling elements to the focus element. By "sibling" we mean a different element which has the same parent to the reference item. By "preceding" we mean a node that ocurrs before the reference one. The order of the preceding-sibling axis is the reverse document order. Take a look at this document:
<fruit>
<banana>
<lady-finger-banana/>
</banana>
<apple/>
<pear/>
<kiwi/>
</fruit>
If the focus node is pear, then the sequence preceding-sibling::* is ...
- apple
- banana
Note: fruit, pear, lady-finger-banana and kiwi are not in the sequence.
So the following is true:
- preceding-sibling::*[ 1] is the apple
- preceding-sibling::*[ 2] is the banana
- count( preceding-sibling::*) is 2
- preceding-sibling::apple[ 1] is also the apple
- preceding-sibling::banana[ 1] is the banana
- preceding-sibling::*[ 3] is absent or the empty sequence
preceding-sibling::pop/ancestor::inventory/totalprice Example
We have to alter your sample document a little bit to usefully study this example
<product>
<inventory>
<drink>
<lemonade>
<price>$2.50</price>
<amount>20</amount>
</lemonade>
<pop>
<price>$1.50</price>
<amount>10</amount>
</pop>
<focus-item />
</drink>
<totalprice>$15</totalprice>
</inventory>
</product>
Let us say the focus is on the element focus-item.
To evaluate the expression preceding-sibling::pop/ancestor::inventory/totalprice follow these steps
- preceding-sibling::pop selects all the preceding pop elements to focus-item. This evaluates to a sequence of one node.
For each item in the left hand sequence (just one pop element it so happens), set this item as a temporary focus item, and evaluate the expression of the right of the / operator which is ...
ancestor::inventory
There is only one such node, which is the ancestral inventory node. Thus the first / operator evaluates to a sequence of one inventory node.
Now we evaluate the effect of the second / and its right-hand operand expression total price. For each item in the left hand sequence (just one inventory node so it happens), set this as a temporary focus item and evaluate totalprice.
- totalprice is short for child::totalprice . There is only one total price element on the child axis of the temporary focus node, so the final result is a sequence of one node, which is the total price node.
Understanding by Diagrams
Please look at this page for an illustration of axises.
Here is a copy of that page's diagram for preceding-sibling:: . In it the reference node is Charlie and the node on the preceding-sibling:: axis is in green. It is the only such node.
Axes useful for navigation through the node tree. So it depends from your problem what kind of axis is useful.
The following stylesheet illustrates the difference.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="snack">
<xsl:variable name="siblings" select="ancestor::node()"/>
<debug>
<xsl:for-each select="preceding-sibling::node()">
<sibling>
<xsl:value-of select="local-name()"/>
</sibling>
</xsl:for-each>
<xsl:for-each select="ancestor::node()">
<ancestor>
<xsl:value-of select="local-name()"/>
</ancestor>
</xsl:for-each>
</debug>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
Preceding-sibling gets all element siblings that preceded it in the current node level. Unless you specify one or more of those preceding siblings with an xpath expression. If you specify a specific preceding-sibling with xpath it always starts with 1 in square brackets.
Ancestor is the first matching ancestor that matches the expression. So it goes back up the node tree to look at a matching expression based on where you currently are pointing. So if you were at product/inventory/drink/pop or just /pop then ancestor inventory/totalprice just looks for the frist occurence and it should only return back a pointer to point to that matching case else it will be pointing to nothing and you'll still be pointing at pop.