Perl script to populate an XML file
I am working on a Perl script which needs to populate a开发者_运维知识库n XML file based on user input. The user would provide a country name and a city name. If he/she provides: japan and e, I need to populate that in the japan tag - but as the last entry. How best can I achieve this? The cities in country tag can be many. How can I add a city as a last tag inside corresponding country tag?
How can I reach at the end of relevant country tag each time I need to add a city?
PS: I am not using any in-built data structures to store data. I am just adding dumb lines in the file.
Samlple output XML file:
<country name="japan-">
<city>a</city>
<city>b</city>
<city>c</city>
<city>d</city>
</country>
<country name="china-">
<city>aa</city>
<city>bb</city>
<city>cc</city>
<city>dd</city>
</country>
I've a more concrete question, Change an XML file content via Perl script.
XML::Simple is... Simple. :) It does require a root element though:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
my $xml = join "\n", <DATA>;
my $doc = XMLin($xml, KeepRoot => 1);
# Get the list of cities as a list, then push "Tokyo" to it.
push @{$doc->{countries}->{country}->{'japan-'}->{city}}, 'Tokyo';
print XMLout($doc, KeepRoot => 1);
__DATA__
<countries>
<country name="japan-">
<city>a</city>
<city>b</city>
<city>c</city>
<city>d</city>
</country>
<country name="china-">
<city>aa</city>
<city>bb</city>
<city>cc</city>
<city>dd</city>
</country>
</countries>
Output:
<countries>
<country name="china-">
<city>aa</city>
<city>bb</city>
<city>cc</city>
<city>dd</city>
</country>
<country name="japan-">
<city>a</city>
<city>b</city>
<city>c</city>
<city>d</city>
<city>Tokyo</city>
</country>
</countries>
Below is a solution using XML::Twig. I think it does what you want. The most notable features of XML::Twig it uses are the use of id => name
option to treat the name attribute as an ID so elements can be found directly with $t->elt_id
, and the insert_new_elt
method to creates a new element in the tree. Its signature is ( <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>
I think you meant: How do I load an XML file and add entries to it based on user input?
If I understood that right: You use a parser/writer like XML::Simple (there are apparently better ones like XML::Twig too, so explore a bit) to load the file into a Perl data structure of hashes and arrays. (Use Data::Dumper to check how it looks like in memory.) Then you edit that structure with normal Perl data interaction and when done use the writer to convert it back to XML.
精彩评论