247

I am new to using XPath and this may be a basic question. Kindly bear with me and help me in resolving the issue. I have an XML file like this:

<RootNode>
  <FirstChild>
    <Element attribute1="abc" attribute2="xyz">Data</Element>
  <FirstChild>
</RootNode>

I can validate the presence of an <Element> tag with:

//Element[@attribute1="abc" and @attribute2="xyz"]

Now I also want to check the value of the tag for string "Data". For achieving this I was told to use:

//Element[@attribute1="abc" and @attribute2="xyz" and Data]

When I use the later expression I get the following error:

Assertion failure message: No Nodes Matched //Element[@attribute1="abc" and @attribute2="xyz" and Data]

Kindly provide me with your advice whether the XPath expression I have used is valid. If not what will be the valid XPath expression?

John Topley
  • 113,588
  • 46
  • 195
  • 237
vcosk
  • 2,894
  • 2
  • 23
  • 23

2 Answers2

366

The condition below:

//Element[@attribute1="abc" and @attribute2="xyz" and Data]

checks for the existence of the element Data within Element and not for element value Data.

Instead you can use

//Element[@attribute1="abc" and @attribute2="xyz" and text()="Data"]
Rashmi Pandit
  • 23,230
  • 17
  • 71
  • 111
38
//Element[@attribute1="abc" and @attribute2="xyz" and .="Data"]

The reason why I add this answer is that I want to explain the relationship of . and text() .

First of all, when using [], there are only two types of data:

  1. [number] to select a node from node-set
  2. [bool] to filter a node-set from node-set

In this case, the value is evaluated to boolean by the function boolean(), and there is a rule:

Filters are always evaluated with respect to a context.

When you need to compare text() or . with a string "Data", it first uses the string() function to transform those to string type, then it gets a boolean result.

There are two important rules about string():

  1. The string() function converts a node-set to a string by returning the string value of the first node in the node-set, which in some instances may yield unexpected results.

    text() is relative path that return a node-set contains all the text node of the current node (context node), like ["Data"]. When it is evaluated by string(["Data"]), it will return the first node of the node-set, so you just get "Data" when there only is one text node in the node-set.

  2. If you want the string() function to concatenate the entire child text, you must pass a single node instead of a node-set.

For example, we get a node-set ['a', 'b'], you can pass their parent node to string(parent), this will return 'ab', and of cause string(.) in your case will return an concatenated string "Data".

Both ways will lead to the same result but only when there is a text node.

fabestah
  • 77
  • 1
  • 1
  • 9
宏杰李
  • 11,820
  • 2
  • 28
  • 35