121

I have the following XML:

<List xmlns="http://schemas.microsoft.com/sharepoint/soap/">
 <Fields>
   <Field>
   </Field>
 </Fields>
</List>

This is a slimmed down version of XML being returned from a SharePoint web service. I also have the following xPath:

/List/Fields/Field

When I remove the xmlns from my XML the xPath works fine. When it's in there my xPath finds nothing. Is there something I should be doing differently with my xPath? Modifying the XML is not an option.

Abe Miessler
  • 82,532
  • 99
  • 305
  • 486
  • You need some level of abstraction... You are asking how to select elements under the default namespace with an XPath expression. **This is the most FAQ**. –  Mar 21 '11 at 16:09
  • See also https://stackoverflow.com/questions/6390339/how-to-query-xml-using-namespaces-in-java-with-xpath – rogerdpack Feb 06 '19 at 23:33
  • See also my canonical answer to [**How does XPath deal with XML namespaces?**](https://stackoverflow.com/q/40796231/290085). It provides an in-depth answer with specific code snippets for most XPath 1.0/2.0 hosting languages and includes an XPath 3.0/3.1 option for using Clark Notation. – kjhughes Dec 09 '22 at 17:41

5 Answers5

134

I also have the following xPath:

/List/Fields/Field 

When I remove the xmlns from my XML the xPath works fine. When it's in there my xPath finds nothing

If you cannot register a namespace binding and cannot use (assuming the registered prefix is "x"):

/x:List/x:Fields/x:Field

then there is another way:

/*[name()='List']/*[name()='Fields']/*[name()='Field']
Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
58

The List element has been defined with a default namespace and this is adopted by all elements inside.

You therefore need to ignore the element namespace like so:

/*[local-name()='List']/*[local-name()='Fields]/*[local-name()='Field]

but this means that the xpath will pick up any other element with List - Fields - Field

You can do a namespace check as well as a local-name check like so:

/*[local-name()='List' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Fields' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Field' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']

Or you can register the namespace with the library and then explicitly specify the prefix for that namespace and add it to xpath expression, the method of which is dependent on the library you are using.

rogermushroom
  • 5,486
  • 4
  • 42
  • 68
  • 2
    This answer is working whereas accepted answer is not working....Thanks @zode64 for this help. I was straggling to get my xpath expression get working for the name space included xml. Now with this I need not to worry anymore about the name space. Thanks a ton.. – Sandeep Mandori Feb 09 '16 at 13:43
  • This should be the accepted answer. It is clear and to the point in contrast to the unnecessary ambiguity of the actual accepted answer. – Alvaro Jan 18 '23 at 19:25
20

You most likely have to register that namespace uri with your xpath library. Depending on the library, you may be able to use the 'default' prefix or you may need to give it a named prefix and use that in your xpath queries.

For example, in php (since you didn't specify a language) using DOMXPath you could do something like this:

$xpath = new DOMXPath($document);
$xpath->registerNamespace('x', 'http://schemas.microsoft.com/sharepoint/soap/');
$xpath->query('/x:List/x:Fields/x:Field');
Anomie
  • 92,546
  • 13
  • 126
  • 145
  • Yeah, I'm a .NET guy and normally my solution would be the .NET equivalent of that. Unfortunately we are using a third party "rapid" development environment that won't give us the ability to do this... – Abe Miessler Mar 09 '11 at 00:03
  • 1
    Also, why do they even include a namespace if there is no prefix? (the `x:` portion of your xPath) – Abe Miessler Mar 09 '11 at 00:03
  • 2
    There is a namespace. It's just using the 'default' prefix in this particular file. The file would be semantically identical were it `` – Anomie Mar 09 '11 at 00:10
  • @Abe Miessler The namespace you've mentioned in your xml is the default namespace for the root element and its child. In your xpath you have to use the same uri namespace, but not the same prefix, which is only a label. If you don't register your namespace, your xpath refers to element with empty uri. You can also register your namespace with empty prefix, so your xpath doesn't need 'x:' prefix. – javanna Mar 09 '11 at 00:16
  • @javanna: I've never been able to convince php's DOMXPath to allow registering a uri for the default prefix, hence the 'x:'. – Anomie Mar 09 '11 at 00:20
  • 1
    The ability to bind namespaces is so fundamental to an XPath library that if your library doesn't provide this capability, you should throw it out. – Michael Kay Mar 09 '11 at 00:25
  • @Anomie I'm sorry, I'm not a php expert. I'm able to do that with Java, using JDom or Dom4J library, and I've supposed this is possible with all languages. Maybe I'm wrong, I don't know all languages :-) – javanna Mar 09 '11 at 00:28
  • @Michael, I agree and this is only the latest in a long line of shortcomings. Unfortunately the company I work for has significant infrastructure built on top of this product so it will be slow to disappear. – Abe Miessler Mar 09 '11 at 00:56
2

I've just been having this issue while using Xalan-c

The bit I didn't quite get initially is that the XPath or XSLT namespace aliases/prefixes can be different to that of the document - depending on your namespace resolver.

It appears that if there is a namespace on the doc, then it fails to match a path element unless a namespace is used. (standard but not always followed?)

The XalanDocumentPrefixResolver will map XPath or XSLT namespaces to URI and try and give them id by getting the prefix - where there is no prefix it used the name which turned into xmlns

/xmlns:List/xmlns:Fields/xmlns:Field

Alternatively you could create your own resolver, but it still requires a minimal namespace used in the xpath :(

Here is one I hacked together while testing, no guarantee of memory

// don't care what prefix given, there can only be the one
struct NoPrefixResolver : public xalanc::PrefixResolver {

    NoPrefixResolver(const xalanc::XalanDOMString&   theURI) : m_uri(theURI){}

    virtual const xalanc::XalanDOMString*
        getNamespaceForPrefix(const xalanc::XalanDOMString&     prefix) const {
        return &m_uri;
    }

    virtual const xalanc::XalanDOMString&   getURI() const {
        return m_uri;
    }

    const xalanc::XalanDOMString    m_uri;
};

/x:List/x:Fields/x:Field 
/a:List/b:Fields/c:Field 
Greg Domjan
  • 13,943
  • 6
  • 43
  • 59
-3

If you can skip the document element, the following XPath can also help:

//Fields/Field

This works as long as you don't have 'Fields' below any other node and as long the sub nodes have no namespace.

David Gausmann
  • 1,570
  • 16
  • 20