解析出节点和属性XML::LibXML

解析出节点和属性XML::LibXML,xml,perl,xpath,xml-libxml,Xml,Perl,Xpath,Xml Libxml,我试图搜索属性的值(xx01)并返回节点(0x100540)。以下是我的xml: <model-response-list error="EndOfResults" throttle="86" total-models="86" xmlns="http://www.ca.com/spectrum/restful/schema/response"> <model-responses> <model mh="0x100540">

我试图搜索属性的值(xx01)并返回节点(0x100540)。以下是我的xml:

  <model-response-list error="EndOfResults" throttle="86" total-models="86" xmlns="http://www.ca.com/spectrum/restful/schema/response">
   <model-responses>
      <model mh="0x100540">
         <attribute id="0x1006e">xxxx01</attribute>
      </model>
      <model mh="0x100c80">
         <attribute id="0x1006e">xxx02</attribute>
      </model>
</model-responses>
</model-response-list>
我已经尝试了每一个xpath搜索,我可以找到一些文档(也许我就是无法理解),但无法找到解决方案

谢谢你的帮助。

这似乎有效

#!/usr/bin/perl

use warnings;
use strict;
use 5.010;

use XML::LibXML;

my $xml = '<model-response-list error="EndOfResults" throttle="86" total-models="86" xmlns="http://www.ca.com/spectrum/restful/schema/response">
   <model-responses>
      <model mh="0x100540">
         <attribute id="0x1006e">xxxx01</attribute>
      </model>
      <model mh="0x100c80">
         <attribute id="0x1006e">xxx02</attribute>
      </model>
</model-responses>
</model-response-list>';

my $xmldoc = XML::LibXML->load_xml( string => $xml );

my @nodes = $xmldoc->findnodes(q(//*[text()='xxxx01']/../@mh));

foreach (@nodes) {
  say $_->value;
}
#/usr/bin/perl
使用警告;
严格使用;
使用5.010;
使用XML::LibXML;
我的$xml文件
xxxx01
xxx02
';
我的$xmldoc=XML::LibXML->load_XML(字符串=>$XML);
my@nodes=$xmldoc->findnodes(q(/*[text()='xxxx01']/../@mh));
foreach(@nodes){
说美元->价值;
}

我的XPath有点生锈了。可能有更好的解决办法。

罪魁祸首几乎肯定是

xmlns="http://www.ca.com/spectrum/restful/schema/response"
XPath中不固定的元素名称指的是不在命名空间中的元素,而文档中的所有元素都在
http://www.ca.com/spectrum/restful/schema/response
namespace,因此

//模型[属性='xxxx01']
将失败。您需要使用
XPathContext
来处理名称空间:

my $xc = XML::LibXML::XPathContext->new($xmldoc);
$xc->registerNs('resp', 'http://www.ca.com/spectrum/restful/schema/response');
my @nodes = $xc->findnodes('//resp:model[resp:attribute = "xxxx01"]');
在XPath表达式中使用传递给
注册表项的前缀。

根据您的

如果没有名称空间,您的目标可以很容易地解决:

my $mh = $xmldoc->findvalue('//model[attribute = "xxxx01"]/@mh');
但是,在XML方面导航更具挑战性的事情之一是名称空间,这是由根节点的
xmlns
属性指定的

我可以推荐两种方法来解决此问题:

  • 在使用查询之前注册命名空间

    以下要求您提前知道名称空间URI

    use XML::LibXML;
    use XML::LibXML::XPathContext;
    
    my $xmldoc = XML::LibXML->load_xml( string => $string);
    my $context = XML::LibXML::XPathContext->new( $xmldoc->documentElement() );
    $context->registerNs( 'u' => 'http://www.ca.com/spectrum/restful/schema/response' );
    
    my $mh = $context->findvalue('//u:model[u:attribute = "xxxx01"]/@mh');
    print "$mh\n";
    
    产出:

    0x100540
    
    0x100540
    
    但是,如果不想硬编码URI,也可以确定名称空间:

    my $ns = ( $xmldoc->documentElement()->getNamespaces() )[0]->getValue();
    $context->registerNs( 'u' => $ns );
    
  • 使用函数查询忽略名称空间:

    这使得XPath更长,但也需要更少的设置:

    use XML::LibXML;
    
    my $xmldoc = XML::LibXML->load_xml( string => $string);
    
    my $mh = $xmldoc->findvalue('//*[local-name() = "model"]/*[local-name() = "attribute"][text() = "xxxx01"]/../@mh');
    print "$mh\n";
    
    产出:

    0x100540
    
    0x100540
    
  • 如果需要一点时间来理解的语法和框架,不要感到气馁。我昨天考虑了名字空间的高级话题,甚至昨天我自己也问过这个问题。


    幸运的是,再多的学习曲线也不会占用您节省的时间来避免可能引入的bug。

    的确如此!非常感谢!