我想使用xPaths解析XML文件。获取节点后,我可能需要在其父节点上执行xPath搜索。我目前使用XML::XPath的代码是:
my $xp = XML::XPath->new(filename => $XMLPath);
# get all foo or foos node with a name
my $Foo = $xp->find('//foo[name] | //foos[name]');
if (!$Foo->isa('XML::XPath::NodeSet') || $Foo->size() == 0) {
# no foo found
return undef;
} else {
# go over each and get its bar node
foreach my $context ($Foo->get_nodelist) {
my $FooName = $context->find('name')->string_value;
$xp = XML::XPath->new( context => $context );
my $Bar = $xp->getNodeText('bar');
if ($Bar) {
print "Got $FooName with $Bar\n";
} else {
# move up the tree to get data from parent
my $parent = $context->getParentNode;
print $parent->getNodeType,"\n\n";
}
}
}
我的目标是获取foo元素名称及其bar子节点值的哈希,如果foo没有bar节点,它应该从其父foo或foos节点获取该节点。
对于这个XML:
<root>
<foos>
<bar>GlobalBar</bar>
<foo>
<name>number1</name>
<bar>bar1</bar>
</foo>
<foo>
<name>number2</name>
</foo>
</foos>
</root>
我希望:
number1->bar1
number2->GlobalBar
使用上面的代码时,我在尝试获取父节点时遇到错误:
无法调用方法“getNodeType” 未定义的值
非常感谢任何帮助!
答案 0 :(得分:5)
当您尝试在undef
上调用方法时,您会看到该错误。在undef
上调用方法的最常见原因是未能检查构造函数方法是否成功。变化
$xp = XML::XPath->new( context => $context );
是
$xp = XML::XPath->new( context => $context )
or die "could not create object with args ( context => '$context' )";
答案 1 :(得分:4)
正如Chas所提到的,你不应该创建第二个XML :: XPath对象(文档也提到了这一点)。你可以传递上下文作为find *方法的第二个参数,或者只是在上下文节点上调用方法,因为你实际上是为了得到$ FooName。
您还有一些方法调用不符合您的想法(getNodeType不返回元素名称,而是返回表示节点类型的数字)。
总体而言,下面的更新代码似乎可以满足您的需求:
#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;
my $xp = XML::XPath->new(filename => "$0.xml");
# get all foo or foos node with a name
my $Foo = $xp->find('//foo[name] | //foos[name]');
if (!$Foo->isa('XML::XPath::NodeSet') || $Foo->size() == 0) {
# no foo found
return undef;
} else {
# go over each and get its bar node
foreach my $context ($Foo->get_nodelist) {
my $FooName = $context->find('name')->string_value;
my $Bar = $xp->findvalue('bar', $context); # or $context->findvalue('bar');
if ($Bar) {
print "Got $FooName with $Bar\n";
} else {
# move up the tree to get data from parent
my $parent = $context->getParentNode;
print $parent->getName,"\n\n";
}
}
}
最后,提醒一句:XML::XPath维护得不好,您可能最好使用XML::LibXML。代码非常相似。