Как упомянул Час, вам не следует создавать второй объект 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 . Код был бы очень похож.