使用命名空间时,XML :: LibXML为什么找不到此xpath查询的节点 [英] Why does XML::LibXML find no nodes for this xpath query when using a namespace

查看:72
本文介绍了使用命名空间时,XML :: LibXML为什么找不到此xpath查询的节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用XPath查询选择一个节点,但我不明白为什么XML :: LibXML在具有xmlns属性时找不到该节点.这是演示该问题的脚本:

I'm attempting to select a node using an XPath query and I don't understand why XML::LibXML doesn't find the node when it has an xmlns atribute. Here's a script to demonstrate the issue:

#!/usr/bin/perl

use XML::LibXML; # 1.70 on libxml2 from libxml2-dev 2.6.16-7sarge1 (don't ask)
use XML::XPath;  # 1.13
use strict;
use warnings;

use v5.8.4; # don't ask

my ($xpath, $libxml, $use_namespace) = @ARGV;

my $xml = sprintf(<<'END_XML', ($use_namespace ? 'xmlns="http://www.w3.org/2000/xmlns/"' : q{}));
<?xml version="1.0" encoding="iso-8859-1"?>
<RootElement>
  <MyContainer %s>
    <MyField>
        <Name>ID</Name>
        <Value>12345</Value>
    </MyField>
    <MyField>
        <Name>Name</Name>
        <Value>Ben</Value>
    </MyField>
  </MyContainer>
</RootElement>
END_XML

my $xml_parser
    = $libxml ? XML::LibXML->load_xml(string => $xml, keep_blanks => 1)
    :           XML::XPath->new(xml => $xml);

my $nodecount = 0;
foreach my $node ($xml_parser->findnodes($xpath)) {
    $nodecount ++;
    print "--NODE $nodecount--\n"; #would use say on newer perl
    print $node->toString($libxml && 1), "\n";
}

unless ($nodecount) {
    print "NO NODES FOUND\n";
}

此脚本允许您在XML :: LibXML解析器和XML :: XPath解析器之间进行选择.它还允许您在MyContainer元素上定义xmlns属性,或者根据传递的参数将其保留.

This script allows you to chose between the XML::LibXML parser and the XML::XPath parser. It also allows you to define an xmlns attribute on the MyContainer element or leave it off depending on the arguments passed.

我正在使用的xpath表达式是"RootElement/MyContainer".当我使用不带名称空间的XML :: LibXML解析器运行查询时,它将找到没有问题的节点:

The xpath expression I'm using is "RootElement/MyContainer". When I run the query using the XML::LibXML parser without the namespace it finds the node with no problem:

benb@enkidu:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' libxml
--NODE 1--
<MyContainer>
    <MyField>
        <Name>ID</Name>
        <Value>12345</Value>
    </MyField>
    <MyField>
        <Name>Name</Name>
        <Value>Ben</Value>
    </MyField>
  </MyContainer>

但是,当我使用适当的名称空间运行它时,它找不到任何节点:

However, when I run it with the namespace in place it finds no nodes:

benb@enkidu:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' libxml use_namespace
NO NODES FOUND

在使用XMLL :: XPath解析器时,将其与输出进行对比:

Contrast this with the output when using the XMLL::XPath parser:

benb@enkidu:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' 0 # no namespace
--NODE 1--
<MyContainer>
    <MyField>
        <Name>ID</Name>
        <Value>12345</Value>
    </MyField>
    <MyField>
        <Name>Name</Name>
        <Value>Ben</Value>
    </MyField>
  </MyContainer>
benb@enkidu:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' 0 1 # with namespace
--NODE 1--
<MyContainer xmlns="http://www.w3.org/2000/xmlns/">
    <MyField>
        <Name>ID</Name>
        <Value>12345</Value>
    </MyField>
    <MyField>
        <Name>Name</Name>
        <Value>Ben</Value>
    </MyField>
  </MyContainer>

这些解析器实现中的哪个实现正确"?为什么使用命名空间时XML :: LibXML会区别对待?命名空间到位后,我该怎么做才能检索节点?

Which of these parser implementations is doing it "right"? Why does XML::LibXML treat it differently when I use a namespace? What can I do to retrieve the node when the namespace is in place?

推荐答案

这是常见问题解答. XPath认为表达式中任何不带前缀的名称都属于无名称空间".

然后,表达式:

RootElement/MyContainer

选择属于无名称空间"的所有MyContainer元素,并且是属于无名称空间"的所有RootElement元素的子元素,并且是上下文(当前节点)的子元素.但是,整个文档中根本没有属于无名称空间"的元素,所有元素都属于默认名称空间.

selects all MyContainer elements that belong to "no namespace" and are children of all RootElement elements that belong to "no namespace" and are children of the context (current node). However, there are no elements at all in the whole document that belong to "no namespace" -- all elements belong to the default namespace.

这说明了您得到的结果. XML :: LibXML 是正确的.

This explains the result you are getting. XML::LibXML is right.

常见解决方案是托管语言的API允许通过注册"命名空间将特定的前缀绑定到命名空间.然后可以使用类似这样的表达式:

The common solution is that the API of the hosting language allows a specific prefix to be bound to the namespace by "registering" a namespace. Then one can use an expression like:

x:RootElement/x:MyContainer

其中x是已注册名称空间的前缀.

where x is the prefix with which the namespace has been registered.

在极少数情况下,托管语言不提供注册名称空间,请使用以下表达式:

In the very rare occasions where the hosting language doesn't offer registering namespaces, use the following expression:

*[name()='RootElement']/*[name()='MyContainer']

这篇关于使用命名空间时,XML :: LibXML为什么找不到此xpath查询的节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆