用于填充XML文件的Perl脚本

时间:2010-11-28 21:34:00

标签: xml perl

我正在研究一个需要根据用户输入填充XML文件的Perl脚本。用户将提供国家名称和城市名称。如果他/她提供:japan和e,我需要在日本标签中填充 - 但作为最后一个条目。我怎样才能做到最好?国家标签中的城市可以很多。如何在相应的国家/地区标记中添加城市作为最后一个标记?

每次需要添加城市时,如何在相关国家/地区标记的末尾显示?

PS:我没有使用任何内置数据结构来存储数据。我只是在文件中添加哑行。

Samlple输出XML文件:

<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>

我有一个更具体的问题, Change an XML file content via Perl script

3 个答案:

答案 0 :(得分:4)

XML::Simple是......简单。 :) 它确实需要一个根元素:

#!/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>

输出:

<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>

答案 1 :(得分:0)

我认为您的意思是:如何根据用户输入加载XML文件并添加条目?

如果我明白这一点:你使用像XML :: Simple这样的解析器/编写器(显然更好的是像XML :: Twig,所以请稍微探讨一下)将文件加载到哈希的Perl数据结构中阵列。 (使用Data :: Dumper检查它在内存中的外观。)然后使用正常的Perl数据交互编辑该结构,完成后使用writer将其转换回XML。

答案 2 :(得分:0)

以下是使用XML::Twig的解决方案。我认为它做你想要的。它使用的XML :: Twig最显着的特性是使用id => name选项将name属性视为ID,因此可以使用$t->elt_idinsert_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>