为什么这个xmlns属性搞砸了我的xpath查询?

时间:2014-11-11 15:56:38

标签: perl xpath libxml2

我正在使用LibXML解析一个简单的jhove输出。但是,我没有得到我期望的价值。这是代码:

use feature "say";
use XML::LibXML;

my $PRSR = XML::LibXML->new();
my $xs=<DATA>; 
say $xs;
my $t1 = $PRSR->load_xml(string => $xs);
say "1:" . $t1->findvalue('//date');
$xs=<DATA>; 
say $xs;
$t1 = $PRSR->load_xml(string => $xs);
say "2:" . $t1->findvalue('//date');


__DATA__
<jhove xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hul.harvard.edu/ois/xml/ns/jhove" xsi:schemaLocation="http://hul.harvard.edu/ois/xml/ns/jhove http://hul.harvard.edu/ois/xml/xsd/jhove/1.3/jhove.xsd" name="Jhove" release="1.0 (beta 3)" date="2005-02-04"><date>2006-10-06T09:11:34+02:00</date></jhove>
<jhove><date>2006-10-06T09:11:34+02:00</date></jhove>

正如您所看到的那样,&#34; 1:&#34;正在返回一个空字符串,而&#34; 2:&#34;正在返回预期日期。 jhove-root-element中的什么使xpath查询无法正常工作?我甚至在XML-Spy中尝试过它,即使有完整的标题也可以。

编辑:当我从根元素中删除xmlns属性时,xpath查询可以正常工作。但那怎么可能呢?

2 个答案:

答案 0 :(得分:5)

XML::LibXML::Node文档专门提到了这个问题以及如何处理它......

  

关于NAMESPACES和XPATH的注释:

     

XPath的一个常见错误是假设节点测试由默认名称空间中没有前缀匹配元素的元素名称组成。这个假设是错误的 - 通过XPath规范,这样的节点测试只能匹配no(即null)命名空间中的元素。

     

因此,例如,人们无法将XHTML文档的根元素与$node->find('/html')匹配,因为'/html'仅在根元素<html>没有命名空间但所有XHTML元素都匹配时才匹配属于命名空间http://www.w3.org/1999/xhtml。 (请注意,xmlns="..."命名空间声明也可以在DTD中指定,这使情况更糟,因为XML文档看起来好像没有默认命名空间。)

     

在XPath中有几种可能的方法来处理命名空间:

     
      
  • 建议的方法是使用XML :: LibXML :: XPathContext模块为XPath评估定义显式上下文,其中可以定义文档无关的前缀到命名空间映射。例如:

    my $xpc = XML::LibXML::XPathContext->new;
    $xpc->registerNs('x', 'http://www.w3.org/1999/xhtml');
    $xpc->find('/x:html',$node);
    
  •   
  • 另一种可能性是使用在查询文档中声明的前缀(如果已知)。如果文档声明了所讨论的命名空间的前缀(并且上下文节点在声明的范围内),则XML :: LibXML允许您在XPath表达式中使用前缀,例如:

    $node->find('/x:html');
    
  •   

答案 1 :(得分:1)

我找到了另一个解决方案。只需使用此

say "1:" . $t1->findvalue('//*[local-name()="date"');

还将找到该值并节省在XPathContext中声明命名空间的麻烦。但除此之外,tobyinks答案是正确的。