How does XPath deal with XML namespaces?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
How does XPath deal with XML namespaces?
If I use
/IntuitResponse/QueryResponse/Bill/Id
to parse the XML document below I get 0 nodes back.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3"
time="2016-10-14T10:48:39.109-07:00">
<QueryResponse startPosition="1" maxResults="79" totalCount="79">
<Bill domain="QBO" sparse="false">
<Id>=1</Id>
</Bill>
</QueryResponse>
</IntuitResponse>
However, I'm not specifying the namespace in the XPath (i.e. http://schema.intuit.com/finance/v3 is not a prefix of each token of the path). How can XPath know which Id I want if I don't tell it explicitly? I suppose in this case (since there is only one namespace) XPath could get away with ignoring the xmlns entirely. But if there are multiple namespaces, things could get ugly.
xml xpath xml-namespaces
|
show 1 more comment
How does XPath deal with XML namespaces?
If I use
/IntuitResponse/QueryResponse/Bill/Id
to parse the XML document below I get 0 nodes back.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3"
time="2016-10-14T10:48:39.109-07:00">
<QueryResponse startPosition="1" maxResults="79" totalCount="79">
<Bill domain="QBO" sparse="false">
<Id>=1</Id>
</Bill>
</QueryResponse>
</IntuitResponse>
However, I'm not specifying the namespace in the XPath (i.e. http://schema.intuit.com/finance/v3 is not a prefix of each token of the path). How can XPath know which Id I want if I don't tell it explicitly? I suppose in this case (since there is only one namespace) XPath could get away with ignoring the xmlns entirely. But if there are multiple namespaces, things could get ugly.
xml xpath xml-namespaces
Your XPath should not return any node : INFO - XPath returned 0 items (compiled in 0ms, evaluated in 1ms). How did you execute the XPath?
– har07
Nov 25 '16 at 0:57
@har07 I did it in Java using importjavax.xml.xpath.XPath. I agree it doesn't work using an online tester. That was one of the perplexing things.
– Adam
Nov 25 '16 at 1:16
Excellent question! XPath itself provides no way to specify a default namespace or the binding of a namespace prefix to a namespace. Fortunately, however, hosting languages and libraries do. See my answer below for details...
– kjhughes
Nov 25 '16 at 1:17
Not quite sure why a question should be upvoted so highly when it has been asked and answered 1000 times before....
– Michael Kay
Nov 25 '16 at 8:52
1
I for one was impressed with this question because, unlike most previous askers, Adam not only included a Minimal, Complete, and Verifiable example, he sensed and conveyed the need for XPath to deal with XML namespaces somehow. Most such questions merely post an XPath, maybe some XML (and if we're lucky it's not an image or a link to a humongous off-site resource), and state that it "doesn't work." Adam sensed it had to do with namespaces, nailed the title, and wrote what I considered to be a question worthy of a canonical answer.
– kjhughes
Nov 25 '16 at 15:59
|
show 1 more comment
How does XPath deal with XML namespaces?
If I use
/IntuitResponse/QueryResponse/Bill/Id
to parse the XML document below I get 0 nodes back.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3"
time="2016-10-14T10:48:39.109-07:00">
<QueryResponse startPosition="1" maxResults="79" totalCount="79">
<Bill domain="QBO" sparse="false">
<Id>=1</Id>
</Bill>
</QueryResponse>
</IntuitResponse>
However, I'm not specifying the namespace in the XPath (i.e. http://schema.intuit.com/finance/v3 is not a prefix of each token of the path). How can XPath know which Id I want if I don't tell it explicitly? I suppose in this case (since there is only one namespace) XPath could get away with ignoring the xmlns entirely. But if there are multiple namespaces, things could get ugly.
xml xpath xml-namespaces
How does XPath deal with XML namespaces?
If I use
/IntuitResponse/QueryResponse/Bill/Id
to parse the XML document below I get 0 nodes back.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3"
time="2016-10-14T10:48:39.109-07:00">
<QueryResponse startPosition="1" maxResults="79" totalCount="79">
<Bill domain="QBO" sparse="false">
<Id>=1</Id>
</Bill>
</QueryResponse>
</IntuitResponse>
However, I'm not specifying the namespace in the XPath (i.e. http://schema.intuit.com/finance/v3 is not a prefix of each token of the path). How can XPath know which Id I want if I don't tell it explicitly? I suppose in this case (since there is only one namespace) XPath could get away with ignoring the xmlns entirely. But if there are multiple namespaces, things could get ugly.
xml xpath xml-namespaces
xml xpath xml-namespaces
edited Nov 25 '16 at 1:18
kjhughes
67.6k1394134
67.6k1394134
asked Nov 25 '16 at 0:43
AdamAdam
2,28562952
2,28562952
Your XPath should not return any node : INFO - XPath returned 0 items (compiled in 0ms, evaluated in 1ms). How did you execute the XPath?
– har07
Nov 25 '16 at 0:57
@har07 I did it in Java using importjavax.xml.xpath.XPath. I agree it doesn't work using an online tester. That was one of the perplexing things.
– Adam
Nov 25 '16 at 1:16
Excellent question! XPath itself provides no way to specify a default namespace or the binding of a namespace prefix to a namespace. Fortunately, however, hosting languages and libraries do. See my answer below for details...
– kjhughes
Nov 25 '16 at 1:17
Not quite sure why a question should be upvoted so highly when it has been asked and answered 1000 times before....
– Michael Kay
Nov 25 '16 at 8:52
1
I for one was impressed with this question because, unlike most previous askers, Adam not only included a Minimal, Complete, and Verifiable example, he sensed and conveyed the need for XPath to deal with XML namespaces somehow. Most such questions merely post an XPath, maybe some XML (and if we're lucky it's not an image or a link to a humongous off-site resource), and state that it "doesn't work." Adam sensed it had to do with namespaces, nailed the title, and wrote what I considered to be a question worthy of a canonical answer.
– kjhughes
Nov 25 '16 at 15:59
|
show 1 more comment
Your XPath should not return any node : INFO - XPath returned 0 items (compiled in 0ms, evaluated in 1ms). How did you execute the XPath?
– har07
Nov 25 '16 at 0:57
@har07 I did it in Java using importjavax.xml.xpath.XPath. I agree it doesn't work using an online tester. That was one of the perplexing things.
– Adam
Nov 25 '16 at 1:16
Excellent question! XPath itself provides no way to specify a default namespace or the binding of a namespace prefix to a namespace. Fortunately, however, hosting languages and libraries do. See my answer below for details...
– kjhughes
Nov 25 '16 at 1:17
Not quite sure why a question should be upvoted so highly when it has been asked and answered 1000 times before....
– Michael Kay
Nov 25 '16 at 8:52
1
I for one was impressed with this question because, unlike most previous askers, Adam not only included a Minimal, Complete, and Verifiable example, he sensed and conveyed the need for XPath to deal with XML namespaces somehow. Most such questions merely post an XPath, maybe some XML (and if we're lucky it's not an image or a link to a humongous off-site resource), and state that it "doesn't work." Adam sensed it had to do with namespaces, nailed the title, and wrote what I considered to be a question worthy of a canonical answer.
– kjhughes
Nov 25 '16 at 15:59
Your XPath should not return any node : INFO - XPath returned 0 items (compiled in 0ms, evaluated in 1ms). How did you execute the XPath?
– har07
Nov 25 '16 at 0:57
Your XPath should not return any node : INFO - XPath returned 0 items (compiled in 0ms, evaluated in 1ms). How did you execute the XPath?
– har07
Nov 25 '16 at 0:57
@har07 I did it in Java using import
javax.xml.xpath.XPath. I agree it doesn't work using an online tester. That was one of the perplexing things.– Adam
Nov 25 '16 at 1:16
@har07 I did it in Java using import
javax.xml.xpath.XPath. I agree it doesn't work using an online tester. That was one of the perplexing things.– Adam
Nov 25 '16 at 1:16
Excellent question! XPath itself provides no way to specify a default namespace or the binding of a namespace prefix to a namespace. Fortunately, however, hosting languages and libraries do. See my answer below for details...
– kjhughes
Nov 25 '16 at 1:17
Excellent question! XPath itself provides no way to specify a default namespace or the binding of a namespace prefix to a namespace. Fortunately, however, hosting languages and libraries do. See my answer below for details...
– kjhughes
Nov 25 '16 at 1:17
Not quite sure why a question should be upvoted so highly when it has been asked and answered 1000 times before....
– Michael Kay
Nov 25 '16 at 8:52
Not quite sure why a question should be upvoted so highly when it has been asked and answered 1000 times before....
– Michael Kay
Nov 25 '16 at 8:52
1
1
I for one was impressed with this question because, unlike most previous askers, Adam not only included a Minimal, Complete, and Verifiable example, he sensed and conveyed the need for XPath to deal with XML namespaces somehow. Most such questions merely post an XPath, maybe some XML (and if we're lucky it's not an image or a link to a humongous off-site resource), and state that it "doesn't work." Adam sensed it had to do with namespaces, nailed the title, and wrote what I considered to be a question worthy of a canonical answer.
– kjhughes
Nov 25 '16 at 15:59
I for one was impressed with this question because, unlike most previous askers, Adam not only included a Minimal, Complete, and Verifiable example, he sensed and conveyed the need for XPath to deal with XML namespaces somehow. Most such questions merely post an XPath, maybe some XML (and if we're lucky it's not an image or a link to a humongous off-site resource), and state that it "doesn't work." Adam sensed it had to do with namespaces, nailed the title, and wrote what I considered to be a question worthy of a canonical answer.
– kjhughes
Nov 25 '16 at 15:59
|
show 1 more comment
1 Answer
1
active
oldest
votes
Defining namespaces in XPath (recommended)
XPath itself doesn't have a way to bind a namespace prefix with a namespace. Such facilities are provided by the hosting library.
It is recommended that you use those facilities and define namespace prefixes that can then be used to qualify XML element and attribute names as necessary.
Here are some of the various mechanisms which XPath hosts provide for specifying namespace prefix bindings to namespace URIs:
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
Perl (LibXML):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python (lxml):
from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python (ElementTree):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
- Remember to call
DocumentBuilderFactory.setNamespaceAware(true). - See also:
Java XPath: Queries with default namespace xmlns
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
See Implementing a User Defined Namespace Resolver:
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
PhP:
Adapted from @Tomalak's answer using DOMDocument:
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
See also @IMSoP's canonical Q/A on PHP SimpleXML namespaces.
C#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
Ruby (Nokogiri):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Note that Nokogiri supports removal of namespaces,
doc.remove_namespaces!
but see the below warnings discouraging the defeating of XML namespaces.
Once you've declared a namespace prefix, your XPath can be written to use it:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
An alternative is to write predicates that test against local-name():
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition
Or, in XPath 2.0:
/*:IntuitResponse/*:QueryResponse/@startPosition
Skirting namespaces in this manner works but is not recommended because it
- Under-specifies the full element/attribute name.
Fails to differentiate between element/attribute names in different
namespaces (the very purpose of namespaces). Note that this concern could be addressed by adding an additional predicate to check the namespace URI explicitly1:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
/@startPosition
1Thanks to Daniel Haley for the
namespace-uri()note.
Is excessively verbose.
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
1
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to callsetNamespaceAware(true)on theDocumentBuilderFactory.
– kjhughes
Nov 25 '16 at 19:56
2
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
1
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
1
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
|
show 3 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f40796231%2fhow-does-xpath-deal-with-xml-namespaces%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Defining namespaces in XPath (recommended)
XPath itself doesn't have a way to bind a namespace prefix with a namespace. Such facilities are provided by the hosting library.
It is recommended that you use those facilities and define namespace prefixes that can then be used to qualify XML element and attribute names as necessary.
Here are some of the various mechanisms which XPath hosts provide for specifying namespace prefix bindings to namespace URIs:
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
Perl (LibXML):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python (lxml):
from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python (ElementTree):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
- Remember to call
DocumentBuilderFactory.setNamespaceAware(true). - See also:
Java XPath: Queries with default namespace xmlns
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
See Implementing a User Defined Namespace Resolver:
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
PhP:
Adapted from @Tomalak's answer using DOMDocument:
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
See also @IMSoP's canonical Q/A on PHP SimpleXML namespaces.
C#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
Ruby (Nokogiri):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Note that Nokogiri supports removal of namespaces,
doc.remove_namespaces!
but see the below warnings discouraging the defeating of XML namespaces.
Once you've declared a namespace prefix, your XPath can be written to use it:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
An alternative is to write predicates that test against local-name():
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition
Or, in XPath 2.0:
/*:IntuitResponse/*:QueryResponse/@startPosition
Skirting namespaces in this manner works but is not recommended because it
- Under-specifies the full element/attribute name.
Fails to differentiate between element/attribute names in different
namespaces (the very purpose of namespaces). Note that this concern could be addressed by adding an additional predicate to check the namespace URI explicitly1:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
/@startPosition
1Thanks to Daniel Haley for the
namespace-uri()note.
Is excessively verbose.
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
1
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to callsetNamespaceAware(true)on theDocumentBuilderFactory.
– kjhughes
Nov 25 '16 at 19:56
2
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
1
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
1
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
|
show 3 more comments
Defining namespaces in XPath (recommended)
XPath itself doesn't have a way to bind a namespace prefix with a namespace. Such facilities are provided by the hosting library.
It is recommended that you use those facilities and define namespace prefixes that can then be used to qualify XML element and attribute names as necessary.
Here are some of the various mechanisms which XPath hosts provide for specifying namespace prefix bindings to namespace URIs:
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
Perl (LibXML):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python (lxml):
from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python (ElementTree):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
- Remember to call
DocumentBuilderFactory.setNamespaceAware(true). - See also:
Java XPath: Queries with default namespace xmlns
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
See Implementing a User Defined Namespace Resolver:
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
PhP:
Adapted from @Tomalak's answer using DOMDocument:
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
See also @IMSoP's canonical Q/A on PHP SimpleXML namespaces.
C#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
Ruby (Nokogiri):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Note that Nokogiri supports removal of namespaces,
doc.remove_namespaces!
but see the below warnings discouraging the defeating of XML namespaces.
Once you've declared a namespace prefix, your XPath can be written to use it:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
An alternative is to write predicates that test against local-name():
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition
Or, in XPath 2.0:
/*:IntuitResponse/*:QueryResponse/@startPosition
Skirting namespaces in this manner works but is not recommended because it
- Under-specifies the full element/attribute name.
Fails to differentiate between element/attribute names in different
namespaces (the very purpose of namespaces). Note that this concern could be addressed by adding an additional predicate to check the namespace URI explicitly1:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
/@startPosition
1Thanks to Daniel Haley for the
namespace-uri()note.
Is excessively verbose.
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
1
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to callsetNamespaceAware(true)on theDocumentBuilderFactory.
– kjhughes
Nov 25 '16 at 19:56
2
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
1
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
1
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
|
show 3 more comments
Defining namespaces in XPath (recommended)
XPath itself doesn't have a way to bind a namespace prefix with a namespace. Such facilities are provided by the hosting library.
It is recommended that you use those facilities and define namespace prefixes that can then be used to qualify XML element and attribute names as necessary.
Here are some of the various mechanisms which XPath hosts provide for specifying namespace prefix bindings to namespace URIs:
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
Perl (LibXML):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python (lxml):
from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python (ElementTree):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
- Remember to call
DocumentBuilderFactory.setNamespaceAware(true). - See also:
Java XPath: Queries with default namespace xmlns
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
See Implementing a User Defined Namespace Resolver:
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
PhP:
Adapted from @Tomalak's answer using DOMDocument:
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
See also @IMSoP's canonical Q/A on PHP SimpleXML namespaces.
C#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
Ruby (Nokogiri):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Note that Nokogiri supports removal of namespaces,
doc.remove_namespaces!
but see the below warnings discouraging the defeating of XML namespaces.
Once you've declared a namespace prefix, your XPath can be written to use it:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
An alternative is to write predicates that test against local-name():
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition
Or, in XPath 2.0:
/*:IntuitResponse/*:QueryResponse/@startPosition
Skirting namespaces in this manner works but is not recommended because it
- Under-specifies the full element/attribute name.
Fails to differentiate between element/attribute names in different
namespaces (the very purpose of namespaces). Note that this concern could be addressed by adding an additional predicate to check the namespace URI explicitly1:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
/@startPosition
1Thanks to Daniel Haley for the
namespace-uri()note.
Is excessively verbose.
Defining namespaces in XPath (recommended)
XPath itself doesn't have a way to bind a namespace prefix with a namespace. Such facilities are provided by the hosting library.
It is recommended that you use those facilities and define namespace prefixes that can then be used to qualify XML element and attribute names as necessary.
Here are some of the various mechanisms which XPath hosts provide for specifying namespace prefix bindings to namespace URIs:
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
Perl (LibXML):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python (lxml):
from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python (ElementTree):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
- Remember to call
DocumentBuilderFactory.setNamespaceAware(true). - See also:
Java XPath: Queries with default namespace xmlns
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
See Implementing a User Defined Namespace Resolver:
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
PhP:
Adapted from @Tomalak's answer using DOMDocument:
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
See also @IMSoP's canonical Q/A on PHP SimpleXML namespaces.
C#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
Ruby (Nokogiri):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Note that Nokogiri supports removal of namespaces,
doc.remove_namespaces!
but see the below warnings discouraging the defeating of XML namespaces.
Once you've declared a namespace prefix, your XPath can be written to use it:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
An alternative is to write predicates that test against local-name():
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition
Or, in XPath 2.0:
/*:IntuitResponse/*:QueryResponse/@startPosition
Skirting namespaces in this manner works but is not recommended because it
- Under-specifies the full element/attribute name.
Fails to differentiate between element/attribute names in different
namespaces (the very purpose of namespaces). Note that this concern could be addressed by adding an additional predicate to check the namespace URI explicitly1:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
/@startPosition
1Thanks to Daniel Haley for the
namespace-uri()note.
Is excessively verbose.
edited Jan 27 at 20:03
answered Nov 25 '16 at 0:58
kjhugheskjhughes
67.6k1394134
67.6k1394134
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
1
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to callsetNamespaceAware(true)on theDocumentBuilderFactory.
– kjhughes
Nov 25 '16 at 19:56
2
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
1
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
1
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
|
show 3 more comments
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
1
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to callsetNamespaceAware(true)on theDocumentBuilderFactory.
– kjhughes
Nov 25 '16 at 19:56
2
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
1
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
1
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
Thank you for such a complete answer. One thing I still don't understand though is how when I use a library like Javax or Pugi XML to parse the XML above with the path I specified, I actually do get results (i.e. a node list) back. Do some of these libraries have an ability to somehow infer simple namespaces?
– Adam
Nov 25 '16 at 17:42
1
1
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to call
setNamespaceAware(true) on the DocumentBuilderFactory.– kjhughes
Nov 25 '16 at 19:56
pugi: nonconformance declaration in docs + odd behavior observation = turn and run / life's too short. Javax: Don't forget to call
setNamespaceAware(true) on the DocumentBuilderFactory.– kjhughes
Nov 25 '16 at 19:56
2
2
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
Turns out pugixml doesn't support xml namespaces at all (stackoverflow.com/questions/1042855/…). Turning and running.
– Adam
Nov 25 '16 at 21:10
1
1
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
@DougGlancy: Sorry, VBA was one of the few examples I'd not yet provided. Remedied by adding now. Note that unqualified attribute names are not automatically placed in the default namespace specified on ancestor elements. I've reopened your other question since other than this detail, you'd already accounted for namespaces properly. Let me know here if I can help in general with XPath and namespaces or over on your question if particular to that issue. Thanks.
– kjhughes
Nov 20 '17 at 4:09
1
1
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
Thanks, very helpful.
– Doug Glancy
Nov 20 '17 at 4:18
|
show 3 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f40796231%2fhow-does-xpath-deal-with-xml-namespaces%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Your XPath should not return any node : INFO - XPath returned 0 items (compiled in 0ms, evaluated in 1ms). How did you execute the XPath?
– har07
Nov 25 '16 at 0:57
@har07 I did it in Java using import
javax.xml.xpath.XPath. I agree it doesn't work using an online tester. That was one of the perplexing things.– Adam
Nov 25 '16 at 1:16
Excellent question! XPath itself provides no way to specify a default namespace or the binding of a namespace prefix to a namespace. Fortunately, however, hosting languages and libraries do. See my answer below for details...
– kjhughes
Nov 25 '16 at 1:17
Not quite sure why a question should be upvoted so highly when it has been asked and answered 1000 times before....
– Michael Kay
Nov 25 '16 at 8:52
1
I for one was impressed with this question because, unlike most previous askers, Adam not only included a Minimal, Complete, and Verifiable example, he sensed and conveyed the need for XPath to deal with XML namespaces somehow. Most such questions merely post an XPath, maybe some XML (and if we're lucky it's not an image or a link to a humongous off-site resource), and state that it "doesn't work." Adam sensed it had to do with namespaces, nailed the title, and wrote what I considered to be a question worthy of a canonical answer.
– kjhughes
Nov 25 '16 at 15:59