无法在Perl中获得最高版本的TRADE

时间:2015-02-11 16:38:18

标签: perl xml-twig

我刚刚开始学习Perl并陷入了危险的境地。输入源XML文件是:

<STATEMENT>
     <TRADE origin = "BANK", ref="1",version="1">
      <EVENT type="PRO">
       <EVENTNAR key = "USE" val = "MY"/>
       <EVENTNAR key = "USEE" val = "MYY"/>
      </EVENT>
     </TRADE>
     <TRADE origin = "BANK", ref="1",version="2">
      <EVENT type="PRO">
       <EVENTNAR key = "USE" val = "MYY"/>
       <EVENTNAR key = "USEE" val = "MYY"/>
      </EVENT>
     </TRADE>
     <TRADE origin = "BANK", ref="2",version="1">
      <EVENT type="PRO">
       <EVENTNAR key = "USE" val = "MY"/>
       <EVENTNAR key = "USEE" val = "MYY"/>
      </EVENT>
         <TRADE origin = "BANK" ref="1",version="1">
           <EVENT type="PRO">
              <EVENTNAR key = "USE" val = "MY"/>
              <EVENTNAR key = "USEE" val = "MYY"/>
           </EVENT>
         </TRADE>
       </TRADE>
    <STATEMENT>

现在我需要使用以下&#39; AND&#39;来过滤交易。条件:

  1. 只与原产地交易=&#34; BANK&#34;

  2. 贸易应该有&#34;类型&#34;属性<EVENT> =&#39; PRO&#39;

  3. 贸易应该有&#34;关键&#34;属性<EVENTNAR> =&#34;使用&#34;

  4. 贸易应该具有&#34;价值&#34;属性<EVENTNAR> =&#34; MY&#34;

  5. 多个<EVENTNAR>可以位于<EVENT>的{​​{1}}下。至少有一个<TRADE>应该是合法的。

  6. 应删除所有子交易,即贸易内贸易:

  7. 最重要的是 - 只能获取给定参考的最高版本号(这不起作用)

  8. 预期产出:

    <EVENTNAR>

    以下是我的代码:

     <STATEMENT>
          <TRADE origin = "BANK", ref="1",version="2">(higher version)
            <EVENT type="PRO">
               <EVENTNAR key = "USE" val = "MYY"/>
               <EVENTNAR key = "USEE" val = "MYY"/>
            </EVENT>
          </TRADE>
          <TRADE origin = "BANK", ref="2",version="1">
            <EVENT type="PRO">
              <EVENTNAR key = "USE" val = "MY"/>
              <EVENTNAR key = "USEE" val = "MYY"/>
            </EVENT>
          </TRADE>
        <STATEMENT>
    

    我的输出是:

    use strict;
      use warnings;
      use XML::Twig;
      use Tie::File;
    
    
        my $SOURCEFILE=$ARGV[0];
        my $FILELOCATIONIN=$ARGV[1];
    
    
        open( my $out, '>:utf8', 'out.xml') or die "cannot create output file out.xml: $!";
    
    
        my $twig = XML::Twig->new(  pretty_print => 'indented',
          twig_handlers => { 'TRADE'=>\&TRADE_HANDLER,
                                'TRADE/TRADE' => \&DEL_TRADE},
                             att_accessors => [ qw/ ref version / ],
    
         );
    
        my %max_version;
    
        $twig->parsefile($FILELOCATIONIN.'/'.$SOURCEFILE.'.xml');
    
    
        for my $trade ($twig->root->children('TRADE')) {
          my ($ref, $version) = ($trade->ref, $trade->version);
        if ($version eq $max_version{$ref})
        {
         $trade->flush($out);
        }
    
        }
    
        sub DEL_TRADE{
        my ( $twig, $TRADE ) = @_;
        $TRADE->delete($TRADE);
        #$twig->purge();
        }
    
    
        sub TRADE_HANDLER {
            my ( $twig, $trade ) = @_;
    
            my $org   = $trade->att('origin');
    
    
         if ($org eq "BANK"  &&  grep {grep {$_->att('key') eq 'USE' and $_->att('value') eq 'MY'}
            $_->children('EVENTNAR')} $trade->children('EVENT[@type="PRO"]') )
    
        {
            my ($ref, $version) = ($trade->ref, $trade->version);
    
            unless (exists $max_version{$ref} and $max_version{$ref} >= $version) {
            $max_version{$ref} = $version;}
    
        }
    
        else
        {
        $twig->purge();
        }
    
        return ;
        }
    

    可以看出,给定引用的最高版本的逻辑不起作用。

    任何建议都将受到高度赞赏。

1 个答案:

答案 0 :(得分:3)

在修复输入后使用XML::XSH2

open file.xml ;
rm //TRADE/TRADE ;
$l = //TRADE[@origin='BANK'][EVENT[@type='PRO'][EVENTNAR[@key='USE'][@val='MY']]] ;
$h := hash @ref $l ;
for my $ref in { keys %$h } {
    $trades = xsh:lookup('h', $ref);
    ls $trades[@version=xsh:max($trades/@version)] ;
} | cat > output1.xml ;

对于非常大的文件,您可以尝试使用流媒体界面:

$h = { {} } ;
stream :f file.xml :F /dev/null select TRADE {
    rm TRADE ;
    if (@origin='BANK'
        and EVENT[@type='PRO'][EVENTNAR[@key='USE'][@val='MY']]
       ) {
        $ref = @ref ;
        $record = xsh:lookup('h', $ref)/@version ;
        perl { $record ||= -1 } ;
        if (@version > $record) {
            $here = . ;
            perl { $h->{$ref} = $here } ;
        }
    }
} ;

create STATEMENT ;
for my $trade in { values %$h } mv $trade into STATEMENT ;
save :f output2.xml ;

在MSWin上,您必须使用NUL而不是/dev/null。该程序仍然可以满足内存 - 它需要记住整个输出。如果它太多了,你必须改变它来处理文件两次:在第一次运行中,它会记住每个ref的最大版本,在第二次运行中,它将输出。

$h = { {} } ;
stream :f file.xml :F /dev/null select TRADE {
    rm TRADE ;
    if (@origin='BANK' 
        and EVENT[@type='PRO'][EVENTNAR[@key='USE'][@val='MY']]
    ) {
        $ref = @ref ;
        $record = xsh:lookup('h', $ref) ;
        perl { $record ||= -1 } ;
        if (@version > $record) {
            $record = @version ;
            perl { $h->{$ref} = $record } ;
        }
    }
} ;

stream :f file.xml :F output3.xml select TRADE {
    rm TRADE ;
    if not(@origin = 'BANK'
           and EVENT[@type='PRO'][EVENTNAR[@key='USE'][@val='MY']]
           and xsh:lookup('h', @ref) = @version
    ) rm . ;
} ;

如果版本+参考组合是唯一的,您可以简化上一个if not中的条件。