对不起,伙计们,我可能会问一个愚蠢的问题,但我不太熟悉Perl或awk(shell编程)中的那个问题。
我的要求是根据某些条件过滤XML。
作为参考,我提供了一个虚拟XML:
<TRADEEXT>
<TRADE origin = "AB" ref = "1" version = "1"/>
<TRADE origin = "AB" ref = "1" version = "2"/>
<TRADE origin = "ABC" ref = "1" version = "1"/>
</TRADEEXT>
现在过滤条件如下:
只有那些必须选择具有origin =“AB”
应用第一个条件后,请务必仅选择那些基于ref的最高版本的TRADES(按引用分组)
因此,带有过滤的TRADES的结果XML必须看起来像
<TRADEEXT>
<TRADE origin = "AB" ref = "1" version = "2"/>
</TRADEEXT>
我设法过滤了原产地为“AB”的TRADES,如下面的代码所示。 但我无法根据给定参考的最高版本过滤TRADES。
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my $twig = new XML::Twig( twig_handlers => { TRADE => \&TRADE } );
$twig->parsefile('1513.xml');
$twig->set_pretty_print('indented');
$twig->print_to_file('out.xml');
sub TRADE {
my ($twig, $TRADE) = @_;
foreach my $c ($TRADE) {
$c->cut($TRADE) unless $c->att('origin') eq "AB";
}
}
任何提示都将受到高度赞赏。
答案 0 :(得分:1)
执行此操作的最明确方法是对XML数据进行两次传递:第一次查找每个version
的最大ref
,第二次删除版本较少的任何元素比最大值。
此程序使用TRADE
twig处理程序构建每%max_version
个最大版本的哈希ref
。它根本不会影响数据的解析。
然后for
循环扫描根元素 TRADE
的所有TRADEEXT
子项,使用delete
删除所有拥有版本不是最大版本。
use strict;
use warnings;
use XML::Twig 3.48;
my $twig = new XML::Twig(
twig_handlers => { '/TRADEEXT/TRADE' => \&trade_handler },
att_accessors => [ qw/ origin ref version / ],
pretty_print => 'indented',
);
my %max_version;
$twig->parsefile('1513.xml');
for my $trade ($twig->root->children('TRADE')) {
my ($ref, $version) = ($trade->ref, $trade->version);
$trade->delete unless $version eq $max_version{$ref};
}
$twig->print_to_file('out.xml');
sub trade_handler {
my ($twig, $trade) = @_;
if ( $trade->origin eq 'AB' ) {
my ($ref, $version) = ($trade->ref, $trade->version);
unless (exists $max_version{$ref} and $max_version{$ref} >= $version) {
$max_version{$ref} = $version;
}
}
1;
}
<强>输出强>
<TRADEEXT>
<TRADE origin="AB" ref="1" version="2"/>
</TRADEEXT>
答案 1 :(得分:0)
好的,首先 - 你错过了一个技巧。
当你使用twig_handler
时,它会“剪掉”一段XML,并将其传递给子程序,并在每次遇到它时都这样做。
所以在你的sub中看到$TRADE
是(解析):
<TRADE origin = "AB" ref = "1" version = "1"/>
因此,foreach
循环没有任何意义。
您可以简化为:
sub TRADE {
my ( $twig, $TRADE ) = @_;
if ( not $TRADE -> att('origin') eq 'AB' ) {
$TRADE -> cut();
}
}
虽然如果你不是paste
,那么你可能想要使用delete()
。
由于您希望根据最高版本保存数据,因此您需要先检查整个数据。一种方法可能是 - 解析XML两次 - 一次提取最高版本。
但是当您使用cut
时,您可以使用paste
。