1

我在一个目录中有许多 XML 文件需要排序并合并到一个文件中。文件格式如下:

文件1.xml:

<?xml version="1.0" encoding="utf-8"?>
<doctypea>
  <header someattr="1">
    <docnumber>111</docnumber>
  </header>
</doctypea>

文件2.xml:

<?xml version="1.0" encoding="utf-8"?>
<doctypea>
  <header someattr="1">
    <docnumber>112</docnumber>
  </header>
</doctypea>

文件 3.xml:

<?xml version="1.0" encoding="utf-8"?>
<doctypeb>
  <header someattr="1">
    <docnumber>111</docnumber>
  </header>
</doctypeb>

文件 4.xml:

<?xml version="1.0" encoding="utf-8"?>
<doctypeb>
  <header someattr="1">
    <docnumber>112</docnumber>
  </header>
</doctypeb>

此目录中的所有文件都需要按照以下标准进行排序:

  1. 文件号码
  2. 文档类型(a 或 b)

然后需要合并它们,所以输出文件应该如下所示:

<?xml version="1.0" encoding="utf-8"?>
<doctypea>
  <header someattr="1">
    <docnumber>111</docnumber>
  </header>
</doctypea>
<doctypeb>
  <header someattr="1">
    <docnumber>111</docnumber>
  </header>
</doctypeb>
<doctypea>
  <header someattr="1">
    <docnumber>112</docnumber>
  </header>
</doctypea>
<doctypeb>
  <header someattr="1">
    <docnumber>112</docnumber>
  </header>
</doctypeb>

为了实现这一点,我尝试在 Perl 中使用 XML:Twig。到目前为止,我有以下代码:

use XML::Twig;

my $xmldir = "/xmlfiles";
my $parser = XML::Twig->new(pretty_print => 'indented');

opendir(DIR, "$xmldir");
my @FILES= readdir(DIR);
closedir(DIR);

foreach (@FILES) {
        if ($_ ne "." && $_ ne "..") {
                print "reading file: $xmldir/$_\n";
                $parser->parsefile("$xmldir/$_");
        }
}

在这一点上,我似乎无法找出正确的语法来从解析器中获取我想要的元素。

1. 如何获取根元素(“doctypea”或“doctypeb”)的值?

2. 我假设我需要 (1) 才能将 parsenode 解析到 docnumber 字段?

然后我的计划是构建某种带有 doctype%number 的 has 以进行排序,我不确定将它们与它合并的最简单方法。

感谢任何建议!

4

2 回答 2

5

请在下面找到可以帮助您入门的小示例。它展示了如何从类似于您的 XML 文件中获取数据(我修复了标签以匹配并引用someattr值以获取有效的 XML)。您可以使用类似的方法来收集您需要的数据并生成输出。

use XML::Twig;

XML::Twig->new(twig_handlers => {
    '/*'        => sub { print $_->gi;           },     # doctypea
    'docnumber' => sub { print $_->trimmed_text; },     # 111
})->parse(\*DATA);    # use parsefile('xxx.xml') to parse a file

__DATA__
<?xml version="1.0" encoding="utf-8"?>
<doctypea>
  <header someattr="1">
    <docnumber>111</docnumber>
  </header>
</doctypea>
于 2011-12-21T15:22:03.677 回答
1

正如 daxim 所注意到的,您的文件不是有效的 XML,但您可以使用正则表达式处理它们。如果文件不是太大,您可以将文件 slurp 成单独的字符串,然后根据它们的内容进行排序。

use File::Slurp qw( read_dir ) ;
my $xmldir=".";
my %files = map {
        s/^.*$//m; 
        /<doctype([ab])>/; my $x=ord($1) - ord('a');
        /<docnumber>(\d+)</docnumber>/; $x += 10*$2;
        $x => $_
    } read_dir($xmldir);
print join("", map { $files{$_} } sort keys %files);

我没有调试过这段代码。也print join("", values %files);可能工作。

于 2011-12-21T15:37:45.870 回答