2009-06-08 4 views
3

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

При использовании приведенного выше кода я получаю сообщение об ошибке при попытке получить родительский узел:

Can» t метод «getNodeType» на неопределенное значение

Любая помощь будет высоко оценена!

ответ

4

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

+0

Спасибо, сейчас он отлично работает. Я рассмотрю XML: LibXML, как вы посоветовали. – Dror

5

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

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

быть

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

Спасибо за этот ответ, но это не проблема. Я знаю, что я получаю сообщение об ошибке для вызова метода undef, вопрос в том, что я делаю неправильно - почему я не могу получить родительский узел? Кстати, конструктор в порядке, я использовал ваш код и не получил никакого сообщения. – Dror

+2

Оффлайн, я бы сказал, ваша проблема в том, что вы уничтожаете исходный объект, назначая $ xp второй раз. –

+0

Я новичок в Perl, Можете ли вы представить образец правильного способа решения этой задачи? – Dror

Смежные вопросы