Question

I've been going at this for hours now. I can't seem to get this right.

I have this sample XML file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<bookstore>

<book category="COOKING">
  <title lang="en">Everyday Italian</title>
  <author>Giada De Laurentiis</author>
  <year>2005</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

</bookstore>

I'm trying use the count() function of XPath to return how many times a value appears in the file (returning a count of elements containing this value).

I can currently use:

count(//*[contains(author, 'J K.')])

And this return '1' which is correct. Now, let's say I don't know in which element or attribute the value I'm searching for resides. If I try to use:

count(//*[contains(/*, 'J K.')])

This returns '25', which is the count of all the nodes in the file. I thought that the first parameter in the contains function in the predicate specifies where to look for the value. However, in this case is appears to signify the value to return. I'm a little confused. I also tried this:

query = "count(//*[contains(/*, 'J K.')]/book/..)";

This also brings back the correct value, but again, you have to know the level at which the value resides. If you have a more complex file with multiple levels for different nodes and you still want to search the entire file, how do you go about doing that?

Was it helpful?

Solution

The is that you're not using the current context inside the predicate, but starting at the root again.


Given you want to query the number of books containing 'J K.', apply contains to the context of all books:

count(//book[contains(., 'J K.')])

If you want to count the number of occurences of tags containing a text node 'J K.', that's easy, too:

count(//*[contains(text(), 'J K.')])

Counting the number of text nodes containing the needle would be easy, too:

count(//text()[contains(., 'J K.')])

Counting the number of occurences of that needle is not possible in XPath 1.0. In XPath 2.0, you would split at occurences of the needle and return the number of occurences minus 1.

count(tokenize(/, 'J K\.'))-1

Remember fn:tokenize() uses regular expressions, so the dot has to be escaped.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top