Ниже приведено решение с использованием XML :: Twig . Я думаю, что он делает то, что вы хотите. Наиболее примечательные особенности XML :: Twig, которые он использует, - это использование опции id => name
для обработки атрибута имени как идентификатора, чтобы элементы можно было найти непосредственно с помощью $t->elt_id
, и метод insert_new_elt
для создания нового элемента в дерево. Его подпись (<position: before, after, first_child or last_child>, <tag_name>, <{attributes}>, <content>
),
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my $t= XML::Twig->new( id => 'name', # treat the name attribute as an ID
pretty_print => 'indented'
)
->parse( \*DATA);
add_city( $t, japan => "Kobe");
add_city( $t, japan => "Tokyo");
add_city( $t, china => "Beijing");
add_city( $t, china => "Shanghai");
add_city( $t, japan => "Kobe");
add_city( $t, south_korea => "Seoul");
$t->print;
sub add_city
{ my( $t, $country_name, $city_name)= @_;
my $country= $t->elt_id( $country_name);
if( ! $country)
{ warn "creating country '$country_name'\n";
$country= $t->root->insert_new_elt( last_child => country
=> { name => $country_name }
);
}
if( $country->first_child( qq{city[text()="$city_name"]}))
{ warn "city '$city_name' already found in '$country_name', skipping\n";
return;
}
warn "adding '$city_name' to '$country_name', skipping\n";
$country->insert_new_elt( last_child => 'city', $city_name);
}
__DATA__
<countries>
<country name="japan">
</country>
<country name="china">
</country>
</countries>