2015-10-15 7 views
-1

Я 2-х недельный пользователь Perl, и я пытаюсь проанализировать вложенный XML-файл размером 300 мб. Поэтому, пожалуйста, извините мою нехватку знаний. Файл следующим образом подобный формат, как показано нижеКак отобразить потомков в XML с помощью Perl XML :: Twig?

<?xml version="1.0" encoding="UTF-8"?> 
    <APP:Report xsi:schemaLocation="WWW" xmlns:xsi="WWW" xmlns:APP="WWW"> 
    <library> 
    <elt> 
    <Book>The book of pages</Book> 
    <Snap></Snap> 
    <Line1>The Beginning</Line1> 
    <Line2>We ceased to exist</Line2> 
    <Line3>Accept it</Line3> 
    <Line4>Now we live</Line4> 
    <Line5>We reject it</Line5> 
    <Rating> 
     <C1>6.1</C1> 
     <C2>8.9</C2> 
     <C3>9.4</C3> 
    </Rating> 
    </elt> 
    <Author>Sally</Author> 
    <Publisher>Penguin</Publisher> 
    <elt> 
    <Book>The song</Book> 
    <Snap></Snap> 
    <Line1>This is how we do it</Line1> 
    <Line2>I hope this works</Line2> 
    <Line3>Please do</Line3> 
    <Line4>Begging you</Line4> 
    <Line5>Bye</Line5> 
    <Rating> 
     <C1>2.3</C1> 
     <C2>9.9</C2> 
     <C3>4.5</C3> 
    </Rating> 
    </elt> 
    <Author>Justin</Author> 
    <Publisher>Victoria</Publisher> 
    </library> 
    </APP:Report> 

Я хочу, чтобы иметь возможность в состоянии отображать книги, SNAP, line1, line2, line3, line4, line5, C1, C2 и C3 в разных столбцах первой строки , Author в строке 2 и Publisher в строке 3. Это всего лишь образец большого файла, который у меня есть. Я не хочу получать доступ к определенному ребенку для отображения. Я хочу показать всех своих потомков.

В настоящее время он печатает все мои строки данных 1 столбец 1. Мой фрагмент кода прилагается ниже. Какой был бы лучший способ сделать это? Я был бы благодарен за любые советы. Спасибо!

my $twig= new XML::Twig(); 
$twig->parsefile($_); # build the twig 
    foreach my $elt ($twig->root->children) 
    { 
    print $fout1 $elt->text."\n"; 
} 

Отредактировано лицо: Что делать, если у меня были вложенные дети в виде гнездовых детей? Что было бы наиболее эффективным для этого? Например, как мне получить доступ к элементам elt для каждого C? Мой второй вопрос о том, как я мог бы отображать эти элементы как

The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C1.X| 
    The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C1.Y| 
    The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C2.X| 
    The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C2.Y| 
    The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C3.X| 
    The book of pages|Snap|Line1|Line2|Line3|Line4|Line5|C3.Y| 
    . 
    . 
    . 
    . 
    . 
    The song|Snap|Line1|Line2|Line3|Line4|Line5|C2.X| 
    The song|Snap|Line1|Line2|Line3|Line4|Line5|C2.Y| 
    Example 
    <Rating> 
     <C1> 
     <elt> 
     <X></X> 
     <X></X> 
     </elt> 
     <elt> 
     <elt> 
     </C1> 
     <C2> 
     <elt> 
     <elt> 
     <elt> 
     </C2> 
     <C3> 
     <elt> 
     <elt> 
     <elt> 
     </C3> 
    </Rating> 

Как Ikegami предложил, самый простой способ сделать это было бы создать обработчик для рейтинга. Но проблема - это время, затраченное на его синтаксический анализ. Файл, который я хочу проанализировать, составляет 300 мб и имеет около 20 таких подпрограмм, как рейтинги. Поэтому я разобрал большую процедуру один раз, а затем разобрал часть большой процедуры 20 раз. Есть ли другой способ сделать это? Есть ли еще один XML-модуль, который может быть более полезным, чем XML :: Twig?

ответ

1

Так вы хотите узлов, в соответствии XPath

descendant:*[count(*)=0] 

ака

.//*[count(*)=0] 

относительно к elt элемента. Я использую XML :: LibXML, поэтому я бы сделал

$elt_node->findnodes("descendant:*[count(*)=0]") 

Аналогичное решение должно быть возможно с помощью XML :: Twig. (У него есть findnodes.)


UG, я забыл, как плохо XML :: Twig поддержка для XPath является. Он не знает о count, а * соответствует не-элементам. Нет проблем, нам просто нужно будет сделать работу самостоятельно.

use strict; 
use warnings; 
use feature qw(say); 

use XML::Twig qw(); 

my @eles = qw(Book Snap Line1 Line2 Line3 Line4 Line5 C1 C2 C3); 

my $twig = XML::Twig->new(
    twig_handlers => { 
     '/APP:Report/library/elt' => sub { 
     my ($twig, $ele) = @_; 

     my %row = 
      map { $_->name() => $_->text() // '' } 
       # $ele->findnodes("descendant:*[count(*)=0]") 
       grep { $_->name() ne '#PCDATA' && (grep { $_->name() ne '#PCDATA' } $_->children) == 0 } 
        $ele->descendants(); 

     say join '|', @row{@eles}; 

     $twig->purge(); # Free unneeded memory. 
     }, 
    }, 
); 

say join '|', @eles;  
$twig->parsefile('my_big.xml'); 

Выход:

Book|Snap|Line1|Line2|Line3|Line4|Line5|C1|C2|C3 
The book of pages||The Beginning|We ceased to exist|Accept it|Now we live|We reject it|6.1|8.9|9.4 
The song||This is how we do it|I hope this works|Please do|Begging you|Bye|2.3|9.9|4.5 
+0

Добавлен мой ответ. – ikegami

+0

Я изумляюсь, насколько это эффективно! Вау. Спасибо! Есть ли другой способ, которым я могу это сделать, не используя twig_handlers, поскольку у меня есть другая часть документа, которую мне тоже нужно проанализировать? – Ppoc

+0

Весь смысл использования XML :: Twig - большая поддержка файлов через 'twig_handlers' – ikegami