Perl: Как считать следующий XML-тег дочерним тегом предыдущего? - PullRequest
0 голосов
/ 30 апреля 2018

В следующем файле данных я хочу рассматривать каждый тег <Field> как дочерний тег <Register> и каждый <Register> как дочерний элемент <Partition>. так что, в основном, я пытаюсь извлечь каждую <Partition> информацию с соответствующими <Register> и <Field>. Поскольку все эти теги являются отдельными и не являются отношениями дочерний и родительский, как я могу получить желаемый результат?

Поскольку файл очень большой, я не хочу делать его дочерним и родительским отношением, так как это потребует поиска / замены и ручного вмешательства.

<Partition>
    <Name>1</Name>
    <Abstract>2</Abstract>
    <Description>3</Description>
    <ParentName>4</ParentName>

    </Partition>
    <Partition>
    <Name>8</Name>
    <Abstract></Abstract>
    <Description>9</Description>
    <ParentName>10</ParentName>

    </Partition>
    <Register>
    <Name>12</Name>
    <Abstract></Abstract>
    <Description>13</Description>
    <ParentName>14</ParentName>

    <Size>32</Size>
    <AccessMode>15</AccessMode>
    <Type>16</Type>


    </Register>
    <Field>
    <Name>17</Name>
    <Abstract></Abstract>
    <Description></Description>
    <ParentName></ParentName>


    </Field>
    <Field>
    .
    .
    .
    </Field>
    <Register>
    .
    .
    .

    </Register>
    <Field>
    .
    .
    .

    </Field>
    <Field>
    .
    .
    .
    </Field>
    <Partition>
        <Name>88</Name>
        <Abstract></Abstract>
        <Description></Description>
        <ParentName>55</ParentName>

    </Partition>
    <Register>
        .
        .
        .

    </Register>
    <Field>
        .
        .
        .

    </Field>
    <Partition>
        .
        .
        .
    </Partition>
    <Partition>
        .
        .
        .
    </Partition>
    <Partition>
       .
       .
       .
    </Partition>
    <Register>
        .
        .
        .
    </Register>

Я использую XML::Twig пакет и вот мой фрагмент кода:

foreach my $register ( $twig->get_xpath('//Register') ) # get each <Register>
    {
        #print $register, "\n";
        my $reg_name = $register->first_child('Name')->text;
        my $reg_abstract= $register->first_child('Abstract')->text;
        my $reg_description= $register->first_child('Description')->text;
       .
       .
       .
          foreach my $xml_field ($register->get_xpath('Field'))
          {
            my $reg_field_name= $xml_field->first_child('Name')->text;
            my $reg_field_abstract= $xml_field->first_child('Abstract')->text;
            #print "$reg_field_name \n";
            .
            .
            .

          }
  }

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Кстати, я написал очень простой код для преобразования Field как ребенка в Register и Register как ребенка в Partition:

use strict;
#use warnings;
use XML::Twig;
use Data::Dumper; 
use Data::Alias;

my $input_xml_file = "gpon.xml";

open (IN_FILE,$input_xml_file);
my @input_file = <IN_FILE>;


for (my $line=0;$line<@input_file;$line++)
{

            if ($input_file[$line] =~ /<\/Partition>/ && $input_file[$line+1] =~ /<Register>/)
            {
                $input_file[$line] = '';

            }
            if ($input_file[$line] =~ /<\/Field>/ && $input_file[$line+1] =~ /<Partition>/)
            {
                $input_file[$line] = "</Field>
</Register>
</Partition>
";

            }
            if ($input_file[$line] =~ /<\/Field>/ && $input_file[$line+1] =~ /<Register>/)
            {
                $input_file[$line] = "</Field>
</Register>
";

            }
            if ($input_file[$line] =~ /<\/Register>/ && $input_file[$line+1] =~ /<Field>/ )
            {
                $input_file[$line] = '';

            }

}
#print OUT_FILE "</Register>";


close(IN_FILE);
open (OUT_FILE,'>gpon_modified.xml');
foreach (@input_file)
{
     print OUT_FILE "$_";
}
print OUT_FILE "</Register>
</Partition>";
close (OUT_FILE);
0 голосов
/ 30 апреля 2018

Согласно вашему комментарию, если вы хотите переписать файл с элементами Register и Field как дочерние элементы Partition, вот что вы можете сделать:

простейшее решение, весь файл загружается в память:

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

my $test_file= 'test.xml';

XML::Twig->new( twig_handlers => { 'Register|Field' => \&child,
                                 },
                pretty_print => 'indented',
              )
          ->parsefile( $test_file)
          ->print;

sub child
  { my( $t, $child)= @_;
    $child->move( last_child => $child->prev_sibling( 'Partition'));
  }

Поскольку вы упомянули, что файл может быть очень большим, ниже приведена несколько более сложная версия, в которой хранятся только 2 Partition элементов памяти (включая новые дочерние элементы первого). Когда Partition анализируется, он использует flush_up_to для очистки дерева, вплоть до предыдущего Partition:

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

my $test_file= 'test.xml';

XML::Twig->new( twig_handlers => { 'Partition' => \&parent,
                                   'Register|Field' => \&child,
                                 },
                pretty_print => 'indented',
              )
          ->parsefile( $test_file);

sub child
  { my( $t, $child)= @_;
    $child->move( last_child => $child->prev_sibling( 'Partition'));
  }

sub parent
  { my( $t, $partition)= @_;
    if( my $prev_partition = $partition->prev_sibling( 'Partition'))
      { $t->flush_up_to( $prev_partition); }
  }

Обратите внимание, что поскольку используется flush_up_to, в конце анализа остальная часть дерева автоматически сбрасывается

Если вам нужно записать XML в определенный файл, вместо STDOUT, вы также можете передать дескриптор файла в flush_up_to.

...