114

I have the following document:

<a>
  <bb>abc</bb>
  <cc>ccc</cc>
  <dd>ddd</dd>
</a>
<a>
  <bb>zz</bb>
  <cc>1</cc>
  <dd>2</dd>
</a>

How can I get the value of <cc> using XPath if <bb> is zz?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
HOE SENGKIANG
  • 1,149
  • 2
  • 8
  • 4
  • 1
    the problem is i know how to access a specific node, but i have no idea of accessing a node if a sibling having specific value. Can it be something like this /a/cc/contains(/a/bb='zz') ? – HOE SENGKIANG Jun 11 '13 at 09:13

6 Answers6

125

Not sure why everybody is querying for siblings, you can also check for <bb/>-elements matching the predicate from <a/>'s predicate:

//a[bb/text() = "zz"]/cc/text()
Sridhar Sarnobat
  • 25,183
  • 12
  • 93
  • 106
Jens Erat
  • 37,523
  • 16
  • 80
  • 96
48

What you need is following-sibling XPath axis

//a/bb[text()="zz"]/following-sibling::cc[1]/text()

Test the Xpath here: http://www.xpathtester.com/obj/b55ec3ac-dfa4-4f44-81e8-f963ea4a0625

Stanley
  • 5,057
  • 4
  • 34
  • 44
  • 5
    @HOESENGKIANG: you should click the check mark to "accept" this answer, or whichever one you think answers the question best. – LarsH Jun 11 '13 at 14:36
31

Q: How to select a node using XPath if sibling node has a specific value?
Because there are only "XPath Axes" for following-siblings and preceding-siblings, you can use one of them if the position is fixed.

But better: Look for cc were the parent has child bb with value 'zz':

//cc[../bb='zz']
Serg
  • 2,346
  • 3
  • 29
  • 38
hr_117
  • 9,589
  • 1
  • 18
  • 23
  • 7
    Either that or `//a[bb = 'zz']/cc`. – Tomalak Jun 11 '13 at 09:31
  • Not sure what you mean by 'only "XPath Axes" for following-sibling and preceding-sibling'. Are you referring to the fact that there is no single axis for all siblings? – LarsH Jun 11 '13 at 14:34
  • @LarsH :Yes sorry, (excuse my bad English :-( ) - that was what I was trying to say. (Because the question was for siblings.) – hr_117 Jun 11 '13 at 14:41
10

First off, your example is not well-formed XML. Overlooking that and that you didn't describe your intents very well (What exactly do you want to select on which condition?), I assume you want to do this:

//cc[preceding-sibling::bb[text()="zz"]]/text()

It selects

TEXT VALUES OF ALL <CC> ELEMENTS
//cc                                    /text()
    THAT HAVE A PRECEDING SIBLING <BB>
    [preceding-sibling::bb             ]
                          THAT HAS TEXT VALUE EQUAL TO "zz"
                          [text()="zz"]

You could write is also as

//bb[text()="zz"]/following-sibling::cc/text()

Please look at the spec, it has some very well readable examples from which you'll learn a lot.

LarsH
  • 27,481
  • 8
  • 94
  • 152
Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
8

Another solution for this problem is

//bb[contains(.,'zz')]/../cc/text()

Explanation: Any bb that contains 'zz' string in all the child nodes of bb then going to parent node of that bb using .., now that we can access the cc so returning text.

I hope that explanation isn't complex.

Saleh Mahmood
  • 1,823
  • 1
  • 22
  • 30
4
//a/cc[../bb='zz']/text()

//a : Selects all 'a' elements no matter where it is.

//a/cc : Selects 'cc' elements that are children of the 'a' element (no matter where a is).

.. : Selects the parent of the current node.

[../bb='zz'] : where value of sibling 'bb' element is zz.

Reference: http://www.w3schools.com/xsl/xpath_syntax.asp

Bae Cheol Shin
  • 1,498
  • 1
  • 11
  • 10