How to select these items using Xpath?

I have a document similar to this:

<root> <A node="1"/> <B node="2"/> <A node="3"/> <A node="4"/> <B node="5"/> <B node="6"/> <A node="7"/> <A node="8"/> <B node="9"/> </root> 

Using xpath, How can I select all elements of B that sequentially follow a given element of A?

This is something like next-silbing :: B, except that I want them to be just the next elements at once.

If I'm on A (node ​​== 1), then I want to select node 2. If I'm on A (node ​​== 3), then I want to choose nothing. If I am on A (node ​​== 4) then I want to select 5 and 6.

Is it possible to do this in xpath? EDIT: It is in the XSL stylesheet select statement.


EDIT2: I do not want to use the node attribute for various elements as a unique identifier. I included the node attribute just to illustrate my point. In the actual XML document, I do not have an attribute that I use as a unique identifier. The Xpath "next-sibling :: UL [previous-sibling :: LI [1] / @ node = current () / @ node]" is the keys in the node attribute, and this is not what I want.

+4
source share
3 answers

Short answer (assuming current () is ok, as it is marked as xslt):

 following-sibling::B[preceding-sibling::A[1]/@node = current()/@node] 

Example stylesheet:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:apply-templates select="/root/A"/> </xsl:template> <xsl:template match="A"> <div>A: <xsl:value-of select="@node"/></div> <xsl:apply-templates select="following-sibling::B[preceding-sibling::A[1]/@node = current()/@node]"/> </xsl:template> <xsl:template match="B"> <div>B: <xsl:value-of select="@node"/></div> </xsl:template> </xsl:stylesheet> 

Good luck

+5
source

While @Chris Nielsen's answer is the right approach, it leaves uncertainty in cases where the attribute being compared is not unique. A more correct way to resolve this issue:

 following-sibling::B[ generate-id(preceding-sibling::A[1]) = generate-id(current()) ] 

This ensures that preceding-sibling::A is identical to the current A , and not just compares some attribute values. Unless you have attributes that are guaranteed to be unique, this is the only safe way.

+3
source

The solution may be to first collect all of the following nodes using the following-sibling::* , grab the first one and require it to be a "B" node.

 following-sibling::*[position()=1][name()='B'] 
+1
source

All Articles