xpath如何处理xml名称空间?

zsbz8rwp  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(371)

xpath如何处理xml名称空间?
如果我使用

/IntuitResponse/QueryResponse/Bill/Id

要解析下面的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 不是路径的每个标记的前缀)。xpath怎么知道是哪个 Id 如果我不说清楚的话我想知道?我想在这种情况下(因为只有一个名称空间),xpath可以忽略 xmlns 完全是。但是如果有多个名称空间,事情可能会变得很糟糕。

vsdwdz23

vsdwdz231#

在xpath中定义名称空间(推荐)

xpath本身没有将命名空间前缀与命名空间绑定的方法。这些设施由托管图书馆提供。
建议您使用这些工具并定义命名空间前缀,然后根据需要使用这些前缀来限定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':'http://schema.intuit.com/finance/v3'})

python(元素树):

namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)

Python(scrapy):

response.selector.register_namespace('i', 'http://schema.intuit.com/finance/v3')
response.xpath('/i:IntuitResponse/i:QueryResponse').getall()

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) .
另请参见:javaxpath:带有默认名称空间xmlns的查询
xmlstarlet公司:

-N i="http://schema.intuit.com/finance/v3"

javascript代码:
请参见实现用户定义的命名空间解析器:

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() 可以免除对客户的需求 nsResolver() .
PHP:
改编自@tomalak使用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");

另请参阅@imsop关于php simplexml名称空间的规范q/a。
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")

注意nokogiri支持移除名称空间,

doc.remove_namespaces!

但是请看下面的警告,这些警告阻止了xml名称空间的失败。
一旦声明了名称空间前缀,就可以编写xpath来使用它:

/i:IntuitResponse/i:QueryResponse

在xpath中消除名称空间(不推荐)

另一种方法是编写测试 local-name() :

/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition

或者,在xpath 2.0中:

/*:IntuitResponse/*:QueryResponse/@startPosition

以这种方式绕过名称空间是可行的,但不建议这样做,因为它
指定完整的元素/属性名称。
无法区分不同名称空间中的元素/属性名称(名称空间的真正用途)。请注意,可以通过添加附加 predicate 来显式检查命名空间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']
/@startPosition

感谢丹尼尔·海利 namespace-uri() 注意。
过于冗长。

nkcskrwz

nkcskrwz2#

我用 /*[name()='...'] 在谷歌的表格中从维基数据中获取一些数据。我有一张这样的table

thes    WD prop links   items
 NOM     P7749   3925    3789
 AAT     P1014   21157   20224

以及cols中的公式 links 以及 items

=IMPORTXML("https://query.wikidata.org/sparql?query=SELECT(COUNT(*)as?c){?item wdt:"&$B14&"[]}","//*[name()='literal']")
=IMPORTXML("https://query.wikidata.org/sparql?query=SELECT(COUNT(distinct?item)as?c){?item wdt:"&$B14&"[]}","//*[name()='literal']")

分别。sparql查询碰巧没有任何空格。。。
我看见了 name() 代替 local-name() 在xml命名空间中破坏我的xpath!,出于某种原因 //*:literal 不起作用。

相关问题