I have some JavaScript/Xpath which isn't working as I would expect. (available on jsfiddle) It would seem that I'm doing something wrong with an XML namespace, preventing me from querying for my elements by their node (tag) names.
If I try querying for all child nodes of the current node, I find the element myElement
without problem:
var xpathResult = xmlDoc.evaluate( "child::*", rootElement, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
var queryEl;
if(queryEl = xpathResult.iterateNext()) {
alert("child::* found element " + queryEl.nodeName);
}
else {
alert("child::* found nothing!");
}
... but if I specifically target the nodes with myElement
node (tag) names I get no results:
/* Now try getting only those children with nodeName `myElement` */
xpathResult = xmlDoc.evaluate( "child::myElement", rootElement, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
var queryEl;
if(queryEl = xpathResult.iterateNext()) {
alert("child::myElement found element " + queryEl.nodeName);
}
else {
alert("child::myElement found nothing!");
}
What am I doing wrong?
The Default NamespaceXPath treats the empty prefix as the null namespace. In other words, only prefixes mapped to namespaces can be used in XPath queries. This means that if you want to query against a namespace in an XML document, even if it is the default namespace, you need to define a prefix for it.
XPath queries are aware of namespaces in an XML document and can use namespace prefixes to qualify element and attribute names. Qualifying element and attribute names with a namespace prefix limits the nodes returned by an XPath query to only those nodes that belong to a specific namespace.
This document describes the interface for using XPath in JavaScript internally, in extensions, and from websites. Mozilla implements a fair amount of the DOM 3 XPath, which means that XPath expressions can be run against both HTML and XML documents.
There is no method to connect a namespace prefix to a namespace in XPath. The hosting library can provide these services. It is strongly advised that we take advantage of those features and create namespace prefixes that may be used to qualify XML element and attribute names as needed.
Try this as your resolver:
var nsResolver = (function (element) {
var
nsResolver = element.ownerDocument.createNSResolver(element),
defaultNamespace = element.getAttribute('xmlns');
return function (prefix) {
return nsResolver.lookupNamespaceURI(prefix) || defaultNamespace;
};
} (xmlDoc.documentElement));
You will also have to select the elements like this:
"child::default:myElement"
// where 'default' can be anything, as long as there is a namespace
Further reading:
Your fiddle: http://jsfiddle.net/chKZc/5/ (updated)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With