Xml Namespace breaking my xpath!
I have the following XML:
<List xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Fields>
<Field>
</Fie开发者_如何学编程ld>
</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.
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']
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.
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');
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
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.
精彩评论