代码之家  ›  专栏  ›  技术社区  ›  Dror Big McLargeHuge

如何使用xml::xpath获取父节点?

  •  3
  • Dror Big McLargeHuge  · 技术社区  · 15 年前

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

    任何帮助都将不胜感激!

    2 回复  |  直到 15 年前
        1
  •  4
  •   Brad Gilbert    15 年前

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

        2
  •  5
  •   Chas. Owens    15 年前

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

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

    成为

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