Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concept XML XLST preceding-sibling and ancestor

Tags:

xml

xslt

xpath

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

like image 645
olo Avatar asked Sep 10 '12 07:09

olo


3 Answers

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 ...

  1. apple
  2. 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:

  1. preceding-sibling::pop selects all the preceding pop elements to focus-item. This evaluates to a sequence of one node.
  2. 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.

  3. 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.

  4. 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

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.

enter image description here

like image 118
Sean B. Durkin Avatar answered Oct 21 '22 02:10

Sean B. Durkin


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> 
like image 39
OkieOth Avatar answered Oct 21 '22 01:10

OkieOth


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.

like image 36
RetroCoder Avatar answered Oct 21 '22 02:10

RetroCoder