我正在尝试搜索属性的值(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
属性指定的。
使用
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 );
使用
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
可能引入的错误的时间。