188

Given this XML, what XPath returns all elements whose prop attribute contains Foo (the first three nodes):

<bla>
 <a prop="Foo1"/>
 <a prop="Foo2"/>
 <a prop="3Foo"/>
 <a prop="Bar"/>
</bla>
Jon Schneider
  • 21,628
  • 17
  • 129
  • 157
ripper234
  • 202,011
  • 255
  • 600
  • 878
  • 1
    Why is everyone looking at the "prop" attribute? Did I miss something? It just says get the first three nodes. –  Sep 19 '08 at 16:28
  • 6
    Everyone is looking at the prop attribute because that's what was asked. Get all nodes where prop contains "Foo". Add and you will see why it isn't just "the first three nodes".. – erlando Sep 19 '08 at 16:34
  • The question in the body is poorly worded, regardless of the title. Can foo really be in any prop attribute, or do you seriously just want the first three nodes? –  Jul 08 '09 at 16:17
  • 3
    Yes, refer to the title please (and feel free to edit). – ripper234 Jul 08 '09 at 18:00
  • If you need case-insensitive comparison see [find-an-element-whose-attribute-contains-a-text-case-insensitively](http://stackoverflow.com/questions/9604057/xpath-to-find-an-element-whose-attribute-contains-a-text-case-insensitively) – Michael Freidgeim Jan 20 '17 at 00:19
  • very good link when using xpaths http://test-able.blogspot.ie/2016/04/xpath-selectors-cheat-sheet.html –  May 30 '17 at 14:37

9 Answers9

325
//a[contains(@prop,'Foo')]

Works if I use this XML to get results back.

<bla>
 <a prop="Foo1">a</a>
 <a prop="Foo2">b</a>
 <a prop="3Foo">c</a>
 <a prop="Bar">a</a>
</bla>

Edit: Another thing to note is that while the XPath above will return the correct answer for that particular xml, if you want to guarantee you only get the "a" elements in element "bla", you should as others have mentioned also use

/bla/a[contains(@prop,'Foo')]

This will search you all "a" elements in your entire xml document, regardless of being nested in a "blah" element

//a[contains(@prop,'Foo')]  

I added this for the sake of thoroughness and in the spirit of stackoverflow. :)

evilhomer
  • 7,656
  • 4
  • 21
  • 21
  • 3
    `xmlme.com` now redirects to some other host and does not appear to host the tool or anything like it. – jpmc26 Dec 06 '17 at 19:28
  • This isn't working. I still get everything: `xidel http://popurls.com/ --extract '//a[contains(@href,'/go/pop')]/@href'` – chovy Dec 29 '20 at 03:11
29

This XPath will give you all nodes that have attributes containing 'Foo' regardless of node name or attribute name:

//attribute::*[contains(., 'Foo')]/..

Of course, if you're more interested in the contents of the attribute themselves, and not necessarily their parent node, just drop the /..

//attribute::*[contains(., 'Foo')]
Alex Beynenson
  • 763
  • 10
  • 9
16
descendant-or-self::*[contains(@prop,'Foo')]

Or:

/bla/a[contains(@prop,'Foo')]

Or:

/bla/a[position() <= 3]

Dissected:

descendant-or-self::

The Axis - search through every node underneath and the node itself. It is often better to say this than //. I have encountered some implementations where // means anywhere (decendant or self of the root node). The other use the default axis.

* or /bla/a

The Tag - a wildcard match, and /bla/a is an absolute path.

[contains(@prop,'Foo')] or [position() <= 3]

The condition within [ ]. @prop is shorthand for attribute::prop, as attribute is another search axis. Alternatively you can select the first 3 by using the position() function.

1729
  • 4,579
  • 2
  • 24
  • 17
6

John C is the closest, but XPath is case sensitive, so the correct XPath would be:

/bla/a[contains(@prop, 'Foo')]
Metro Smurf
  • 33,866
  • 20
  • 97
  • 127
4

Have you tried something like:

//a[contains(@prop, "Foo")]

I've never used the contains function before but suspect that it should work as advertised...

toddk
  • 831
  • 1
  • 9
  • 20
4

If you also need to match the content of the link itself, use text():

//a[contains(@href,"/some_link")][text()="Click here"]

SomeDudeSomewhere
  • 3,878
  • 1
  • 20
  • 25
2

/bla/a[contains(@prop, "foo")]

David Hill
  • 4,062
  • 2
  • 21
  • 18
2

try this:

//a[contains(@prop,'foo')]

that should work for any "a" tags in the document

Dani Duran
  • 746
  • 5
  • 6
1

For the code above... //*[contains(@prop,'foo')]

digiguru
  • 12,010
  • 18
  • 59
  • 83