Как использовать XML :: XPath для получения родительского узла? - PullRequest
3 голосов
/ 08 июня 2009

Я хочу проанализировать XML-файлы, используя xPaths. После получения узла мне может потребоваться выполнить поиск 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 ]

5 голосов
/ 08 июня 2009

Вы увидите эту ошибку при попытке вызвать метод на undef. Самая распространенная причина вызова метода в undef - это неспособность проверить, был ли метод конструктора успешным. Изменение

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

будет

$xp = XML::XPath->new( context => $context )
    or die "could not create object with args ( context => '$context' )";
4 голосов
/ 08 июня 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...