XPath如何处理XML名称空间?
XPath如何处理XML名称空间?
如果我使用
/IntuitResponse/QueryResponse/Bill/Id parsing下面的XML文档,我得到0个节点。
 <?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> 
 但是,我没有在XPath中指定名称空间(即http://schema.intuit.com/finance/v3不是path中每个标记的前缀)。 如果我没有明确地告诉XPath XPath如何知道我想要的Id ? 我想在这种情况下(因为只有一个名称空间),XPath可以完全忽略xmlns 。 但是,如果有多个命名空间,事情可能会变得丑陋。 
在XPath中定义名称空间(推荐)
XPath本身没有办法将名称空间前缀与名称空间绑定。 这些设施由托pipe图书馆提供。
build议您使用这些工具并定义名称空间前缀,然后根据需要使用它们来限定XML元素和属性名称。
以下是XPath主机为命名空间URI指定名称空间前缀绑定所提供的各种机制:
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':'/i:IntuitResponse/i:QueryResponse'}) 
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)。
- 另请参见: Java XPath:使用默认名称空间xmlns进行查询
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); 
xmlstarlet:
 -N i="http://schema.intuit.com/finance/v3" 
JavaScript的:
请参阅实现用户定义的名称空间parsing器 :
 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的:
改编自@ Tomalak的回答 :
 $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"); 
一旦声明了名称空间前缀,就可以编写XPath来使用它:
 /i:IntuitResponse/i:QueryResponse 
击败XPath中的命名空间(不推荐)
 另一种方法是编写用于testinglocal-name()谓词: 
 /*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition 
或者,在XPath 2.0中:
 /*:IntuitResponse/*:QueryResponse/@startPosition 
以这种方式踢脚本命名空间的作品,但不推荐,因为它
- 低于指定完整的元素/属性名称。
- 
无法区分不同名称空间中的元素/属性名称(命名空间的目的)。 请注意,可以通过添加一个额外的谓词来显式检查名称空间URI来解决此问题1 : /*[ namespace-uri()='http://schema.intuit.com/finance/v3' and local-name()='IntuitResponse'] /*[ namespace-uri()='http://schema.intuit.com/finance/v3' and local-name()='QueryResponse'] /@startPosition1感谢Daniel Haley提供的 namespace-uri()注释。
- 
过于冗长。