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 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 occurs 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 ...
Note: fruit, pear, lady-finger-banana and kiwi are not in the sequence.
So the following is true:
preceding-sibling::*[ 1]
is the applepreceding-sibling::*[ 2]
is the bananacount( preceding-sibling::*)
is 2preceding-sibling::apple[ 1]
is also the applepreceding-sibling::banana[ 1]
is the bananapreceding-sibling::*[ 3]
is absent or the empty sequenceWe 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.Here is a 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With