this is a follow-up question of my previous thread:
Please help me on understanding this XPath
I have an XPath as:
<xsl:value-of select="position()+count(preceding-sibling::*)-18"/>
currently I can only understand the parts of it, like position(). Also, I know that preceding-sibling is to choose all siblings before the current node, but I have no idea what the statement mean when they get combined like above.
Could anyone give some help on understanding this XPath? thanks in advance.
Your expresion is doing some calculation using the static position (from input source) and the dynamic position (from current node list).
Lets see some examples. Suppose this stylesheet and this input:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="list">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:value-of select="concat(position(),' + ',
count(preceding-sibling::*),' = ',
position() +
count(preceding-sibling::*))"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<list>
<a/>
<b/>
<a/>
<b/>
</list>
Output:
<list>
<a>1 + 0 = 1</a>
<b>2 + 1 = 3</b>
<a>3 + 2 = 5</a>
<b>4 + 3 = 7</b>
</list>
Now, changing the second rule to match="a":
<list>
<a>1 + 0 = 1</a>
<a>3 + 2 = 5</a>
</list>
So, patterns don't change the current node list
What if position() is in pattern? Lets change the rule to match="a[position()=2]":
<list>
<a>3 + 2 = 5</a>
</list>
Strange? No. In the XPath pattern position() works against its own context node list and the axis direction. This case: child::a[position()=2] meaning a second a child.
This shows that position() in patterns works with different context than position() in the content template.
So, How change the current context node list? Well, apply-templates and for-each instructions.
Add now to the apply-templates instruction some select attribute like select="a":
<list>
<a>2 + 2 = 4</a>
</list>
All answers with the exception of @Alejandro 's have the same common fault:
It is not true that:
preceding-sibling::*
selects all preceding-sibling nodes.
It only selects all preceding-sibling elements.
To select all preceding-sibling nodes use:
preceding-sibling::node()
There are these kind of nodes in XPath:
The root node (denoted as /), also denoted as document-node() in XPath 2.0
Element nodes. such as <a/>
Text nodes. In <a> Hello </a> the text node is the only child of a and has a string value of " Hello "
Comment nodes. <!-- This is a comment-->
Processing instruction nodes. <?someName I am a PI ?>
Attribute nodes. In <a x="1"/> x is the only attribute of a.
Namespace nodes. <a xmlns:my="my:namespace"/> a has a namespace node with value "my:namespace" and name (prefix) my
Nodes of the first 5 kinds can be selected using the preceding-sibling:: axis:
preceding-sibling::node()
selects all sibling nodes of kind 1 to 5.
preceding-sibling::*
selects all element preceding siblings
preceding-sibling::someName
selects all elemens named "someName" preceding siblings
preceding-sibling::text()
selects all text nodes preceding siblings (useful in mixed content)
preceding-sibling::comment()
selects all comment node preceding siblings.
preceding-sibling::processing-instruction()
selects all preceding siblings that are PIs
preceding-sibling::processing-instruction('someName')
selects all preceding siblings that are PIs and are named "someName".
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