我需要合并两个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条目的位置。
答案 0 :(得分:1)
下面的代码将使用XML :: Twig
执行此操作它可以使用2个以上的文档,即使并非所有的ID都存在于两个文档中,它也能正常工作。它会将两个文件加载到内存中,如果您希望能够使用太大而无法放入内存的文档,则代码会更复杂一些。行将与第一个文档中的顺序相同,然后在第二个文档中(对于仅出现在第二个文档中的行)。
由于它是作为测试编写的,因此您可以使测试用例更复杂,或添加更多测试,这可能是一个好主意。
#!/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;
}