XML :: twig用于过滤PERL中的XML父节点

时间:2015-01-06 18:43:53

标签: perl xml-twig

我有一个xml代码段

<head>
 <a>
   <b  attr_1=1>
   <b  attr_1=2>
     <c  attr_2 =3  attr_3 =5/>
     <c  attr_2 =4  attr_3 =6 />
  </b>
 </a>
<a>
   <b  attr_1=1/>
   <b  attr_1=3>
     <c  attr_2 =3  attr_3 =5/>
     <c  attr_2 =10  attr_3 =10/ >
   </b>
 </a>
</head>

现在只有那些拥有<b attr_1 =3>(至少一个)并且至少有一个<c> attr_2=10attr_3 =10的孩子才合法的节点是合法的。 因此,输出文件应具有以下交易

   <a>
       <b  attr_1=1/>
       <b  attr_1=3>(this is the legitimate value)
         <c  attr_2 =3  attr_3 =5/>
         <c  attr_2 =10  attr_3 =10/ >(this is the legitimate combination)
       </b>  
   </a>

我的代码是

use strict;
use warnings;
use XML::Twig;

my $twig = new XML::Twig( twig_handlers => { a=> \&a} );
$twig->parsefile('1511.xml');
$twig->set_pretty_print('indented');
$twig->print_to_file('out.xml');

    sub a {

        my ( $twig, $a ) = @_ ;

        $a->cut
         unless grep { $_->att( 'attr_1' ) eq '3' } $a->children( 'b' )

    }

通过这个我能够达到水平。如果有人能够解释如何遍历和grep直到节点B内的节点C,请提供帮助。

1 个答案:

答案 0 :(得分:2)

您的XML文件中存在一些错误。您似乎也删除了描述的某些部分。您还可以为处理程序和*child方法设置一些属性限制。

sub a {

  my ( $twig, $a ) = @_ ;
  my $cut = 1;

  foreach my $b ($a->children('b[@attr_1="3"]')){
    $cut &&= not grep {$_->att('attr_2') eq '10'
                   and $_->att('attr_3') eq '10'} $b->children('c');
  }


  $a->cut if $cut;
}

这是我用于测试的文件:

<head>
<a>
   <b  attr_1="1" />
   <b  attr_1="2">
     <c  attr_2 ="3"  attr_3 ="5"/>
     <c  attr_2 ="4"  attr_3 ="6" />
  </b>
</a>
<a>
   <b  attr_1="1"/>
   <b  attr_1="3">
     <c  attr_2 ="3"  attr_3 ="5"/>
     <c  attr_2 ="10"  attr_3 ="10" />
   </b>
 </a>
<a>
   <b  attr_1="1"/>
   <b  attr_1="3">
     <c  attr_2 ="3"  attr_3 ="5"/>
     <c  attr_2 ="10"  attr_3 ="12" />
   </b>
 </a>
</head>

输出:

<head>
  <a>
    <b attr_1="1"/>
    <b attr_1="3">
      <c attr_2="3" attr_3="5"/>
      <c attr_2="10" attr_3="10"/>
    </b>
  </a>
</head>

编辑:如果你真的只想要grep个语句,你可以使用这样的嵌套greps,不过我建议你使用上面更可读的解决方案。< / p>

$a->cut unless
  grep {grep {$_->att('attr_2') eq '10' and $_->att('attr_3') eq '10'}
    $_->children('c')} $a->children('b[@attr_1="3"]');