【问题标题】:How to use XML::XPath to get parent node?如何使用 XML::XPath 获取父节点?
【发布时间】:2009-06-08 12:19:54
【问题描述】:

我想使用 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” 未定义值

任何帮助将不胜感激!

【问题讨论】:

    标签: xml perl xpath


    【解决方案1】:

    当您尝试在 undef 上调用方法时,您将看到该错误。在undef 上调用方法的最常见原因是未能检查构造方法是否成功。改变

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

    成为

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

    【讨论】:

    • 感谢您的回答,但这不是问题所在。我知道我收到尝试调用 undef 方法的错误消息,问题是我做错了什么 - 为什么我无法获取父节点?顺便说一句,构造函数没问题,我使用了你的代码,没有收到任何消息。
    • 副手,我想说你的问题是你通过第二次分配给 $xp 来破坏原始对象。
    • 我是 Perl 新手,你能提供一个处理手头任务的正确方法的示例吗?
    【解决方案2】:

    正如 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。代码将非常相似。

    【讨论】:

    • 谢谢 - 现在工作正常。我会按照你的建议研究 XML:LibXML。
    猜你喜欢
    • 2015-10-03
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 2015-03-30
    • 1970-01-01
    • 1970-01-01
    • 2016-05-04
    • 2014-01-26
    相关资源
    最近更新 更多