How can I select an element with multiple classes with Xpath?
In the above xml sample I would like to select all the books that belong to class foo and not in class bar by using xpath.
<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
<book class="foo">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book class="foo bar">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book class="foo bar">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<开发者_开发技巧;year>2005</year>
<price>29.99</price>
</book>
</bookstore>
By padding the @class
value with leading and trailing spaces, you can test for the presence of " foo " and " bar " and not worry about whether it was first, middle, or last, and any false positive hits on "food" or "barren" @class
values:
/bookstore/book[contains(concat(' ',@class,' '),' foo ')
and not(contains(concat(' ',@class,' '),' bar '))]
Although I like Mads solution: Here is another approach for XPath 2.0:
/bookstore/book[
tokenize(@class," ")="foo"
and not(tokenize(@class," ")="bar")
]
Please note that the following expressions are both true:
("foo","bar")="foo" -> true
("foo","bar")="bar" -> true
XPath 2.0:
/*/*[for $s in concat(' ',@class,' ')
return
matches($s, ' foo ')
and
not(matches($s, ' bar '))
]
Here no tokenization is done and $s is calculated only once.
Or even:
/*/book[@class
[every $t in tokenize(.,' ') satisfies $t ne 'bar']
[some $t in tokenize(.,' ') satisfies $t eq 'foo']
]
精彩评论