解析节点和属性XML::LibXML



我正在尝试搜索属性的值(xxxx01)并返回节点(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>

我有xml在var下面的代码:

#Get restful req
  $client->setHost('http://wltsvpnms02.aigfpc.com:8080');
  $client->GET('/spectrum/restful/devices?attr=0x1006e', $headers) || die  "$!";
  my $parser     = XML::LibXML->new();
  my $xmldoc     = XML::LibXML->load_xml( string => $client->responseContent() )|| die "$!";

我已经尝试了每一个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;
}

我的XPath有点生疏。也许有更好的解决办法。

罪魁祸首几乎肯定是

xmlns="http://www.ca.com/spectrum/restful/schema/response"

XPath中的无前缀元素名指的是不在名称空间中的元素,而文档中的所有元素都在http://www.ca.com/spectrum/restful/schema/response名称空间中,因此像

这样明显的路径
//model[attribute = '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表达式中传递给registerNs的前缀

根据你对其他问题的建议,XML::LibXML是一个很好的选择。

如果没有名称空间,您的目标可以像这样简单地解决:

my $mh = $xmldoc->findvalue('//model[attribute = "xxxx01"]/@mh');

然而,更具有挑战性的事情之一是名称空间,这是由根节点的xmlns属性指定的。

我可以推荐两种方法来解决这个问题:
  1. 使用XML::LibXML::XPathContext查询前先注册命名空间

    下面的操作要求您提前知道名称空间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 "$mhn";
    

    输出:

    0x100540
    

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

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

    这使得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 "$mhn";
    

    输出:

    0x100540
    

如果需要一段时间才能理解XPath语法和XML::LibXML的框架,不要感到气馁。我认为名称空间是高级主题,甚至昨天我自己也问了一个关于它们的问题。

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

相关内容

  • 没有找到相关文章

最新更新