2015-03-05 3 views
1

Я использую XML :: Twig для анализа XML-файла и печати некоторой информации. Вот мой XML-файл:Perl: Получить несколько дочерних элементов элемента XPath

<report> 
    <reportheader> 
     <month>February 2015</month> 
     <dateofgeneration>20/02/2015 - 12:29:02</dateofgeneration> 
    </reportheader> 
</report> 

и у меня есть следующий код:

XML::Twig->new(
    twig_handlers => { 
     '/report/reportheader' => sub { 
      printf qq|%s\n|, $_->text; 
     }, 
    }, 
)->parsefile($ARGV[0]); 

К сожалению, это печатает February 201520/02/2015 - 12:29:02. Есть ли способ разделить эти два, а не объединять их? Я надеялся сделать что-то вроде:

printf qq|Month: %s\nDate: %s\n|, $_->text[0], $_->text[1]; 

, чтобы разделить его на две переменные, но это не сработало.

+0

не так просто бы ' '/ отчет/reportheader/*' 'для выбора? «Текст» или «значение» элемента Element - это, как правило, конкатенация текстового контента из себя и всех детей. – user2864740

+0

Ваша модификация работала немного. Теперь он печатает их на отдельных строках, но я хочу иметь другой текст, предшествующий им, т. Е. «Месяц: февраль 2015 г. \ nДата: 20/02/2015 ....' – Bijan

+2

Вы должны иметь возможность проверить имя текущего узла. Или вы можете создать обработчик для каждого узла. – ikegami

ответ

3

Я намеревался написать ответ на вопрос your previous question, который показал, как проще избежать системы обратного вызова XML::Twig вообще для чего угодно, кроме огромных файлов данных XML. Я добавил that answer сейчас, и вам может понравиться посмотреть.

Такой же подход подходит и для этой проблемы. Это просто вопрос нахождения всех элементов /report/reportheader и печати текстового содержимого их (первых) month и dateofgeneration дочерних элементов.

Вот рабочий пример. Обратите внимание, что предполагается, что два дочерних элемента будут всегда существуют. Если это не относится к вашим фактическим данным, вам может потребоваться сначала проверить их существование, но обратите внимание, что first_child_trimmed_text (и его братья) просто вернет пустую строку без жалобы, если указанный узел не существует.

use strict; 
use warnings; 
use 5.010;  # For `say` 

use XML::Twig; 

my $twig = XML::Twig->new; 
$twig->parsefile(shift @ARGV); 

for my $report_header ($twig->findnodes('/report/reportheader')) { 
    say $report_header->first_child_trimmed_text('month'); 
    say $report_header->first_child_trimmed_text('dateofgeneration'); 
} 

выход

February 2015 
20/02/2015 - 12:29:02 
+0

Благодарим вас за ответ. Мне это нравится больше, чем у меня в настоящее время. Быстрый вопрос, чтобы не задавать другой вопрос. Можно ли использовать findnodes для поиска всех узлов «месяца» и сохранения их в массиве? – Bijan

+2

@Bijan: Конечно. Вы должны написать 'my @months = $ twig-> findnodes ('// month')', чтобы найти все элементы 'month' в любом месте XML-документа. Похоже, вы могли бы использовать учебник [XPath] (http://archive.oreilly.com/pub/a/perl/excerpts/system-admin-with-perl/ten-minute-xpath-utorial.html), но пожалуйста, избегайте W3Schools, что в первую очередь представляет собой создание денег, а не источник информации с целостностью. Лучше всего [сам RFC] (http://www.w3.org/TR/xpath/) – Borodin

+0

Есть ли однострочный шрифт, чтобы просто загрузить текст из результатов? 'my @months = $ twig-> findnodes ('// month') -> text()' дает мне "Cant текст объекта объекта объекта" Я бы предпочел не использовать foreach для загрузки '$ _-> text () ' – Bijan