views:

5601

answers:

4

I'm trying to use XPath to find all elements that have an element in a given namespace.

For example, in the following document I want to find the foo:bar and doodah elements

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:foo="http://foo.example.com"&gt;
  <foo:bar quux="value">Content</foo:bar>
  <widget>Content</widget>
  <doodah foo:quux="value">Content</doodah>
</root>

I know I can use the following XPath expression to load all attributes from a given namespace

"//@*[namespace-uri()='http://foo.example.com']"

However:

  • This doesn't give me the elements, just the attributes and
  • where elements contain multiple attributes from that namespace, this XPath will return a result per-attribute rather than per-element

Is it possible to get what I want, or do I just have to gather the attributes and calculate the unique set of elements they correspond to ?

EDIT: I was given the following answer by Dimitre Novatchev. I didn't realise that you could nest predicates inside predicates like this:

"//*[@*[namespace-uri()='http://foo.example.com']]"

Specifically this says "Any element that has any attribute that has namespace-uri = '...'"

+1  A: 

Not sure if this is what you mean, but by only deleting 1 char in your XPath you get all elements in a certain namespace:

//*[namespace-uri()='http://foo.example.com']
jor
does not match attrubutes in that namespace
Johannes Weiß
A: 

You could try

//*[namespace-uri()='http://foo.example.com' or @*[namespace-uri()='http://foo.example.com']]

It will give you element foo:bar and element doodah (if you change tal:quux to foo:quux in your XML-data):

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:foo="http://foo.example.com" xmlns:tal="xxx">
  <foo:bar quux="value">Content</foo:bar>
  <widget>Content</widget>
  <doodah foo:quux="value">Content</doodah>
</root>

is that what you want?

EDIT: Thanks for spotting the attribute mistake, corrected now.

Johannes Weiß
Not quite so... namespace-uri(./@*)='http://foo.example.com'] returns true only if the first attribute (which is implementation dependent!) belongs to that namespace. The original post wants the element to be selected if *any* of its attributes belongs to the namespace
Dimitre Novatchev
Oops, good spot with the tal I left in there by mistake
Gareth
A: 

Your XPath expression is almost perfect. Instead of asking for attributes "@" ask for elements "" and it should work:

"//*[namespace-uri()='http://foo.example.com']"
potyl
You haven't understood the question. The OP wants any element to be selected, that either belongs to the namespace or has ot least one attribute that belongs to the namespace. Your expression doesnt select an element that has attributes in the namespace but the element doesnt belong to the namespace
Dimitre Novatchev
Thanks for the clarification. I know that I haven't understood the question as I added a comment to the question asking why "doodah" should be selected.
potyl
+8  A: 

Use:

  //*[namespace-uri()='yourNamespaceURI-here'
     or
      @*[namespace-uri()='yourNamespaceURI-here']
     ]

the predicate two conditions are or-ed with the XPath or operator.

The XPath expression thus selects any element that either:

  • belongs to the specified namespace

or

  • has attributes that belong to the specified namespace
Dimitre Novatchev
It was only the second half of that I needed :) I didn't know you could nest predicates in predicates. Have updated my post accordingly
Gareth