Как я могу объединить два файла XML в один? - PullRequest
1 голос
/ 14 февраля 2012

Мне нужно объединить два файла XML.Я видел этот вопрос раньше, но этот автор хотел просто объединить два файла.Я хочу объединить на основе определенного дочернего элемента, в данном случае, id.

У меня есть два XML-файла, имеющие следующую структуру:

Файл № 1:

<document>
  <row>
      <id>1</id>
      <data_field1>aaaa</data_field1>
      <data_field2>bbbb</data_field2>
   </row>
</document>

Файл № 2:

<document>
  <row>
      <id>1</id>
      <data_field3>cccc</data_field3>
   </row>
</document>

ИЯ хочу, чтобы они были объединены в Файл № 3:

<document>
  <row>
      <id>1</id>
      <data_field1>aaaa</data_field1>
      <data_field2>bbbb</data_field2>
      <data_field3>cccc</data_field3>
   </row>
</document>

Где он использует элемент id для присоединения к каждой записи XML.

1 Ответ

1 голос
/ 14 февраля 2012

Код ниже сделает это, используя XML :: Twig

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

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

#!/usr/bin/perl

use strict;
use warnings;

use Test::More;
use XML::Twig;

# normally you would read the documents from file, 
# but it's easier to write a self-contained test
my $d1='
<document>
<row>
<id>1</id>
<data_field1>aaaa</data_field1>
<data_field2>bbbb</data_field2>
</row>
</document>
';

my $d2='
<document>
<row>
<id>1</id>
<data_field3>cccc</data_field3>
</row>
</document>
';

my $merged=
'<document>
<row>
<id>1</id>
<data_field1>aaaa</data_field1>
<data_field2>bbbb</data_field2>
<data_field3>cccc</data_field3>
</row>
</document>
';
$merged=~ s{\n}{}g; # remove \n's, 
                    # if you want the result indented, look at the pretty_print option

is( merged( $d1, $d2), $merged, 'one test to rule them all');

done_testing();


sub merged
  { 
    my @docs= map { XML::Twig->new->parse( $_) } @_;

    my $merged= XML::Twig->new->parse( '<document></document>');

    my %row_id; # hash id => row_element

    foreach my $doc (@docs)
      { foreach my $row ($doc->root->children( 'row'))
          { my $eid= $row->first_child( 'id');
            my $id= $eid->text;
            # if the row hasn't been created in the merged doc, do it
            if( ! $row_id{$id})
              { $row_id{$id}= $merged->root->insert_new_elt( last_child => 'row');
                $row_id{$id}->insert_new_elt( last_child => id => $id);
              }
            # move the data fields to the end of the row
            foreach my $data_field ($eid->next_siblings) 
              { $data_field->move( last_child => $row_id{$id}); }
          }
      }
    return $merged->sprint;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...