tags:

views:

41

answers:

1

I'm looking for a way to concatenate two arbitrary, valid XPath expressions to build a new XPath expression.

Effectively I'd like to apply the second XPath expression on the result of the first XPath expression.

For example, take this XML:

<foo>
  <bar>
    <baz />
  </bar>
<foo>

The XPath expression /foo would obviously return the root element, while /bar would return nothing. But /bar applied to the result of /foo should return the <bar>element.

Now the naive implementation would be to just use String concatenation to build /foo/bar and evaluate that to get <bar>. This works in this specific case.

Now my question is: is it always that simple? Are there any types of XPath expressions where this won't result in a valid expression or would lead to unexpected results?

It isn't much of a problem if some obscure XPath expressions can't be validated that way, but I'd like the common ones to work.

If there are problems: Is there any kind of concatenation that works in more situations?

+2  A: 

In XPath 1.0 the / operator requires that its operand to the left is of type that selects a nodeset and its operand to the right is a relative XPath expression -- also is of type selecting a nodeset.

Therefore, any expr1 that evaluates to a simple value (number, string, boolean) cannot be used to the left of /. This is exactly true for the right-hand-side argument of /.

Examples of invalid XPath 1.0 expressions:

string(/foo)/bar

count(//foo)/bar

(/foo/baz = 3)/bar

/foo/count(bar)

In XPath 2.0 it is still required that in expr1/expr2 expr1 must evaluate to a node-set. However, expr2 can be a function call. Thus the following are valid and have meaningful results:

/foo/bar/string-length(.) (: a sequence of integers that are the string lengths of every /foo/bar node :)

/foo/bar/name(.) (: a sequence of strings that are the names of every /foo/bar node :)

foo/bar/count(node()) (: a sequence of integers that are the number of children nodes of every /foo/bar node :)

There are other connectors that may be used to combine two expressions to produce a third one:

In both XPath 1.0 and XPath 2.0:

The union operator:

expr1 | expr2

The comparison operators:

expr1 = expr2
expr1 >= expr2
expr1 < expr2
expr1 <= expr2
expr1 != expr2

The boolean operators and the not() function:

not(expr1)

expr1 and expr2

expr1 or expr2

In XPath 2.0:

the operators except, intersect union

Dimitre Novatchev
Great answer, thanks! I was only thinking of expressions that select node sets (because those are most important to me), so I missed a big chunk!
Joachim Sauer
@Joachim-Sauer: Glad my answer was useful. Consider accepting it? :)
Dimitre Novatchev