我正在尝试搜索属性的值(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>
我在下面的代码中有一个var中的xml:
#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搜索,我可以找到一些文档(也许我只是无法理解它),但无法提出解决方案。
感谢您的帮助。
答案 0 :(得分:1)
这似乎有效。
#!/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有点生疏。可能有更好的解决方案。
答案 1 :(得分:1)
罪魁祸首几乎可以肯定是
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
的前缀。
答案 2 :(得分:1)
根据XML::LibXML
的建议other question做出选择。
如果没有命名空间,您的目标可以像以下一样轻松解决:
my $mh = $xmldoc->findvalue('//model[attribute = "xxxx01"]/@mh');
然而,导航XML的更具挑战性的事情之一是命名空间,正如根节点的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 "$mh\n";
输出:
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 "$mh\n";
输出:
0x100540
如果需要一点时间来吸收XPath语法和XML::LibXML
的框架,请不要气馁。我认为名称空间是高级主题,甚至昨天我自己也问过a question。
幸运的是,没有多少学习曲线会占用您节省的时间,以避免XML::Simple
会引入的错误。