简体   繁体   English

如何使用XML :: XPath获取父节点?

[英]How to use XML::XPath to get parent node?

I want to parse XML files using xPaths. 我想使用xPaths解析XML文件。 After getting a node I may need to perform xPath searches on their parent nodes. 获取节点后,我可能需要在其父节点上执行xPath搜索。 My current code using XML::XPath is: 我目前使用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";
        }
    }
}

My goal is to get a hash of foo elements names and their bar child nodes values, if a foo does not have a bar node it should get the one from its parent foo or foos node. 我的目标是获取foo元素名称及其bar子节点值的哈希,如果foo没有bar节点,它应该从其父foo或foos节点获取该节点。

For this XML: 对于这个XML:

<root>
    <foos>
        <bar>GlobalBar</bar>
        <foo>
            <name>number1</name>
            <bar>bar1</bar>
        </foo>
        <foo>
            <name>number2</name>
        </foo>
    </foos>
</root>

I would expect: 我希望:

number1->bar1 
number2->GlobalBar

When using the above code I get an error when trying to get parent node: 使用上面的代码时,我在尝试获取父节点时收到错误:

Can't call method "getNodeType" on an undefined value 无法在未定义的值上调用方法“getNodeType”

Any help will be much appreciated! 任何帮助都感激不尽!

You will see that error when you try to call a method on undef . 当您尝试在undef上调用方法时,您将看到该错误。 The most common reason for calling a method on undef is failure to check to see if the constructor method was successful. undef上调用方法的最常见原因是无法检查构造函数方法是否成功。 Change 更改

$xp = XML::XPath->new( context => $context );

to be 成为

$xp = XML::XPath->new( context => $context )
    or die "could not create object with args ( context => '$context' )";

As Chas mentioned, you should not create a second XML::XPath object (the docs mention this too). 正如Chas所提到的,你不应该创建第二个XML :: XPath对象(文档也提到了这一点)。 You can either pass pass the context as the second parameter of the find* methods, or simply call the methods on the context node, as you in fact did to get $FooName. 你可以传递上下文作为find *方法的第二个参数,或者只是调用上下文节点上的方法,因为你实际上是为了获得$ FooName。

You also have a few method calls that don't do what you think (getNodeType doesn't return the element name, but a number representing the node type). 您还有一些方法调用不符合您的想法(getNodeType不返回元素名称,而是返回表示节点类型的数字)。

Overall the updated code below seems to give you what you want: 总的来说,下面的更新代码似乎可以满足您的需求:

#!/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";
        }
    }
}

Finally, a word of warning: XML::XPath is not well maintained, and you would probably be better off using XML::LibXML instead. 最后,提醒一句: XML :: XPath维护得不好,你最好还是使用XML :: LibXML The code would be very similar. 代码非常相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM