Surender Thakran
Surender Thakran

Reputation: 4054

How to select the first preceding-sibling which has a particular node as child?

I have been trying to write a XPath statement which will select the first preceding-sibling of a node. That sibling should have a particular node as its child.

For example:

<a>
    <c></c>
    ....
    <b></b>
</a>

<a></a>
....
....
<a></a>

<a>
   <b> start </b>
</a>

In the above XML, if my context is at the node a which has start text inside its child b. How can I select the preceding node a whose child is b?

I tried preceding-sibling::*[b][1] but it only selects the node a if b is its first child. I also tried preceding-sibling::*[1][b] but it only checks the first preceding a node and if it doesn't contains b, the test fails.

Note: I am using XSLT 1.0

Can anyone suggest me a solution?

Thnx in advance!!

Upvotes: 5

Views: 16754

Answers (3)

Tomalak
Tomalak

Reputation: 338148

Like this. ("The first preceding sibling who has a <b> child"):

preceding-sibling::a[b][1]

or this ("The first preceding sibling but only if it has a <b> child"):

preceding-sibling::a[1][b]

Multiple predicates must be true one after another. Therefore, this:

preceding-sibling::a[b and position() = 1]

is equivalent to the second expression, but not to the first.

Upvotes: 7

michael.hor257k
michael.hor257k

Reputation: 116982

I believe that:

preceding-sibling::*[b][1]

or preferably:

preceding-sibling::a[b][1]

should work just fine.

I tried preceding-sibling::*[b][1] but it only selects the node a if b is its first child.

I don't think that is so.

Upvotes: 8

Joel M. Lamsen
Joel M. Lamsen

Reputation: 7173

With this input:

<root>
    <a>
        <c></c>
        <b>SUCCESS</b>
    </a>
    <a>FAIL</a>
    <a>FAIL</a>
    <a>
        <b> start </b>
    </a>
</root>

and this stylesheet

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="a[b[.=' start ']]">
        <xsl:copy>
        <xsl:value-of select="preceding-sibling::a[b]"/>
        </xsl:copy>

    </xsl:template>
</xsl:stylesheet>

it outputs

<root>
   <a>
      <c/>
      <b>SUCCESS</b>
   </a>
   <a>FAIL</a>
   <a>FAIL</a>
   <a>SUCCESS</a>
</root>

Upvotes: 1

Related Questions