解析问题,使用XML :: XPath的
问题描述:
我试图解析XML文件(serverslist2.xml)与包含在格式的服务器列表:解析问题,使用XML :: XPath的
<?xml version="1.0"?>
<servers>
<aplication name="App1">
<env name="Test">
<appliance alias="app1t1" conname="10.0.0.10:80" />
<appliance alias="app1st1" conname="10.0.0.10:443" />
</env>
<env name="Prod">
<appliance alias="app1p1" conname="10.0.1.10:80" />
<appliance alias="app1sp1" conname="10.0.1.10:443" />
<appliance alias="app1p2" conname="10.0.1.11:80" />
<appliance alias="app1sp2" conname="10.0.1.11:443" />
</env>
</aplication>
<aplication name="App2">
<env name="Test">
<appliance alias="app2t1" conname="10.0.0.20:80" />
<appliance alias="app2st1" conname="10.0.0.20:443" />
</env>
<env name="Prod">
<appliance alias="app2p1" conname="10.0.1.20:80" />
<appliance alias="app2sp1" conname="10.0.1.20:443" />
<appliance alias="app2p2" conname="10.0.1.21:80" />
<appliance alias="app2sp2" conname="10.0.1.21:443" />
</env>
</aplication>
</servers>
我可能会收到一个“别名”值(我知道它是唯一的)在一个变量中,并需要检索“conname”值。
到目前为止,我的代码(testxpath.pl)看起来像:
#!/usr/bin/perl
use XML::XPath;
my $file = 'serverslist2.xml';
my $xp = XML::XPath->new(filename => $file);
my $server = app2st1;
print "Starting Test1:\n";
foreach my $test1 ($xp->find('//appliance[@alias="' . $server . '"]')->get_nodelist) {
print "Test1 output: " , $test1->find('@conname') , "\n";
} ;
print "Starting Test2:\n";
my $test2 = $xp->find('//appliance[@alias="' . $server . '"]')->get_nodelist ;
print "Test2 output: " , $test2->find('@conname') , "\n";
好奇的是,测试1,使用foreach科,工,但是没有它,它失败了,即使使用基本相同命令。
输出是:
$ ./testxpath.pl
Starting Test1:
Test1 output: 10.0.0.20:443
Starting Test2:
Can't call method "find" without a package or object reference at ./testxpath.pl line 16.
有人能澄清什么是错的,如何解决? 此外,如果有更好的方法使用这个或其他Perl的XML处理库,它将不胜感激。 (P.S:我可能不是简单的“grep”可以使用一些正则表达式,因为XML将始终符合这个标准,但不一定会被“印刷精美”)
问候 雷纳托
答
->get_nodelist
返回一个列表。
因此你必须把你的变量在括号或它只会被分配名单count,而不是第一个值:
my ($test2) = $xp->find(qq{//appliance[\@alias="$server"]})->get_nodelist;
或者,因为你只是在寻找一个值,你可以使用该findvalue
方法:
print "Starting Test3:\n";
my $conname = $xp->findvalue(qq{//appliance[\@alias="$server"]/\@conname});
print "Test3 output: $conname\n";
这是一个完整的工作的工作脚本了:
#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;
my $file = 'serverslist2.xml';
my $xp = XML::XPath->new(xml => do { local $/; <DATA> });
my $server = 'app2st1';
print "Starting Test1:\n";
foreach my $test1 ($xp->find(qq{//appliance[\@alias="$server"]})->get_nodelist) {
print "Test1 output: ", $test1->find('@conname'), "\n";
}
print "Starting Test2:\n";
my ($test2) = $xp->find(qq{//appliance[\@alias="$server"]})->get_nodelist;
print "Test2 output: ", $test2->find('@conname'), "\n";
print "Starting Test3:\n";
my $conname = $xp->findvalue(qq{//appliance[\@alias="$server"]/\@conname});
print "Test3 output: $conname\n";
__DATA__
<?xml version="1.0"?>
<servers>
<aplication name="App1">
<env name="Test">
<appliance alias="app1t1" conname="10.0.0.10:80" />
<appliance alias="app1st1" conname="10.0.0.10:443" />
</env>
<env name="Prod">
<appliance alias="app1p1" conname="10.0.1.10:80" />
<appliance alias="app1sp1" conname="10.0.1.10:443" />
<appliance alias="app1p2" conname="10.0.1.11:80" />
<appliance alias="app1sp2" conname="10.0.1.11:443" />
</env>
</aplication>
<aplication name="App2">
<env name="Test">
<appliance alias="app2t1" conname="10.0.0.20:80" />
<appliance alias="app2st1" conname="10.0.0.20:443" />
</env>
<env name="Prod">
<appliance alias="app2p1" conname="10.0.1.20:80" />
<appliance alias="app2sp1" conname="10.0.1.20:443" />
<appliance alias="app2p2" conname="10.0.1.21:80" />
<appliance alias="app2sp2" conname="10.0.1.21:443" />
</env>
</aplication>
</servers>
输出:
Starting Test1:
Test1 output: 10.0.0.20:443
Starting Test2:
Test2 output: 10.0.0.20:443
Starting Test3:
Test3 output: 10.0.0.20:443
findvalue()的工作原理与我在找的一样。这是一个更优雅的解决方案。 Tkx Miller。 – Renato 2014-09-04 02:47:53
关于'findvalue'的另外一个发现是: 对于打印来说,工作很好,但对于任务我发现这样做效果更好: 'my $ conname = $ xp-> findvalue(qq {// appliance [\ @ alias = “$服务器”]/\ @ CONNAME}) - >值(); ' 这是因为'findvalue'返回'XML :: XPath :: Literal'对象而不是字符串,因为'value()'会做。 – Renato 2014-09-04 20:31:10
是的,['findvalue'](https://metacpan.org/pod/XML::XPath#findvalue-path-context)返回['XML :: XPath :: Literal'](https:// metacpan。组织/ POD/XML :: XPath的::文字)。您可以使用[' - > value()'](https://metacpan.org/pod/XML::XPath::Literal#value)来访问字符串表示,但也可以通过quote运算符重载。 ' “$ CONNAME”' – Miller 2014-09-04 20:41:24