XPath 1.0/2.0
Defining namespaces in XPath (recommended)
XPath 本身没有办法将名称空间前缀与名称空间绑定。此类设施由托管图书馆提供。
建议您使用这些工具并定义命名空间前缀,然后可以根据需要使用这些前缀来限定 XML 元素和属性名称。
以下是 XPath 主机提供的一些用于指定命名空间前缀绑定到命名空间 URI 的各种机制。
(OP's original XPath, /IntuitResponse/QueryResponse/Bill/Id
, has been elided to /IntuitResponse/QueryResponse
.)
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);
谷歌文档:
很遗憾,IMPORTXML() https://support.google.com/docs/answer/3093342?hl=en不提供命名空间前缀绑定机制。请参阅下一节,击败 XPath 中的命名空间,了解如何使用local-name()
作为解决方法。
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";
// ...
}
});
- 记得打电话DocumentBuilderFactory.setNamespaceAware(true) http://docs.oracle.com/javase/6/docs/api/javax/xml/parsers/DocumentBuilderFactory.html#setNamespaceAware%28boolean%29.
- 也可以看看:Java XPath:使用默认名称空间 xmlns 进行查询 https://stackoverflow.com/questions/10720452/java-xpath-queries-with-default-namespace-xmlns
JavaScript:
See 实现用户定义的命名空间解析器 https://developer.mozilla.org/en-US/docs/Introduction_to_using_XPath_in_JavaScript#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 );
请注意,如果默认命名空间定义了关联的命名空间前缀,则使用nsResolver()
由返回Document.createNSResolver() https://developer.mozilla.org/en-US/docs/Web/API/Document/createNSResolver可以消除对客户的需求nsResolver()
.
Perl (LibXML http://search.cpan.org/dist/XML-LibXML/lib/XML/LibXML/XPathContext.pod):
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 http://lxml.de/xpathxslt.html#namespaces-and-prefixes):
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 (元素树 https://stackoverflow.com/q/14853243/290085):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Python (Scrapy http://doc.scrapy.org/en/latest/index.html):
response.selector.register_namespace('i', 'http://schema.intuit.com/finance/v3')
response.xpath('/i:IntuitResponse/i:QueryResponse').getall()
PhP:
改编自@Tomalak 使用 DOMDocument 的回答 https://stackoverflow.com/a/6475568/290085:
$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");
也可以看看@IMSoP 关于 PHP SimpleXML 命名空间的规范问答 https://stackoverflow.com/q/44894426/290085.
红宝石(野科切):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
请注意,Nokogiri 支持删除名称空间,
doc.remove_namespaces!
但请参阅以下警告,阻止破坏 XML 命名空间。
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)
SoapUI (doc https://www.soapui.org/docs/functional-testing/validating-messages/validating-xml-messages/):
declare namespace i='http://schema.intuit.com/finance/v3';
/i:IntuitResponse/i:QueryResponse
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
一旦声明了命名空间前缀,就可以编写 XPath 来使用它:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
另一种方法是编写谓词来测试local-name()
:
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']
或者,在 XPath 2.0 中:
/*:IntuitResponse/*:QueryResponse
以这种方式绕过命名空间是可行的,但不推荐,因为它
-
未指定完整的元素/属性名称。
-
无法区分不同元素/属性名称
命名空间(命名空间的真正目的)。请注意,可以通过添加额外的谓词来显式检查名称空间 URI 来解决此问题:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
Thanks to Daniel Haley https://stackoverflow.com/users/317052/daniel-haley for the namespace-uri()
note.
-
过于冗长。
XPath 3.0/3.1
支持现代 XPath 3.0/3.1 的库和工具允许直接在 XPath 表达式中指定命名空间 URI:
/Q{http://schema.intuit.com/finance/v3}IntuitResponse/Q{http://schema.intuit.com/finance/v3}QueryResponse
While Q{http://schema.intuit.com/finance/v3}
比使用 XML 命名空间前缀详细得多,它的优点是独立于托管库的命名空间前缀绑定机制。这Q{}
符号被称为克拉克符号以它的创始人詹姆斯·克拉克 (James Clark) 命名。 W3C XPath 3.1 EBNF 语法将其称为BracedURILiteral https://www.w3.org/TR/xpath-31/#prod-xpath31-BracedURILiteral.
Thanks to Michael Kay https://stackoverflow.com/users/415448/michael-kay for the suggestion to cover XPath 3.0/3.1's BracedURILiteral
.