Concept XML XLST preceding-sibling and ancestor
Solution 1
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 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 ...
- 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 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 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 precedingpop
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 forchild::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
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.
Solution 2
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>
Solution 3
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.
olo
Updated on April 11, 2020Comments
-
olo about 4 years
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