2016-05-17 10 views
2

XML::Twigを学び、XMLドキュメントからデータを取得しようとしています。XML :: Twigを使用して不要な要素をスキップする方法は?

私のXMLには20k + <ADN>要素が含まれています。 Eaach <ADN>要素には数十の子要素が含まれ、そのうちの1つは<GID>です。

ハンドラは、一定の順序でトリガーされ、そのタイプによってソート(XPathの :私はGID == 1(たとえば、XMLが__DATA__ある参照)

は、ドキュメントは言うのみADNプロセスをしたいです最初に正規表現、次に正規表現、次にレベル)、次に (ルート要素で始まる)フルパスを指定するかどうかによって、 式のステップ数、述部の数、次に のテスト数述語。最後のステップがないハンドラ ステップ(foo/bar/*)が他のXPathハンドラの後にトリガされます。 最後にすべてハンドラが最後にトリガされます。

重要:それはとにかく と呼ばれるすべてハンドラを除き、何らの 他のハンドラが呼び出されていない0を返した場合、ハンドラがトリガされた後。

私の実際のコード:そう

$VAR1 = { 
      '1000' => { 
        'ID' => '1000', 
        'Name' => 'other name 1000' 
        }, 
      '1' => { 
       'Name' => 'name 1', 
       'ID' => '1' 
       }, 
      '20' => { 
        'Name' => 'should be skipped because GID != 1', 
        'ID' => '20' 
       } 
     }; 

出力

use 5.014; 
use warnings; 
use XML::Twig; 
use Data::Dumper; 

my $cat = load_xml_catalog(); 
say Dumper $cat; 

sub load_xml_catalog { 
     my $hr; 
     my $current; 
     my $twig= XML::Twig->new(
     twig_roots => { 
      ADN => sub {  # process the <ADN> elements 
       $_->purge; # and purge when finishes with one 
      }, 
     }, 
     twig_handlers => { 
      'ADN/GID' => sub { 
       return 1 if $_->trimmed_text == 1; 
       return 0;  # skip the other handlers - if the GID != 1 
      }, 

      'ADN/ID' => sub { #remember the ID as a "key" into the '$hr' for the "current" ADN 
       $current = $_->trimmed_text; 
       $hr->{$current}{$_->tag} = $_->trimmed_text; 
      }, 

      #rules for the wanted data extracting & storing to $hr->{$current} 
      'ADN/Name' => sub { 
       $hr->{$current}{$_->tag} = $_->text; 
      }, 
     }, 
     ); 
     $twig->parse(\*DATA); 
    return $hr; 
} 
__DATA__ 
<ArrayOfADN> 
    <ADN> 
     <GID>1</GID> 
     <ID>1</ID> 
     <Name>name 1</Name> 
    </ADN> 
    <ADN> 
     <GID>2</GID> 
     <ID>20</ID> 
     <Name>should be skipped because GID != 1</Name> 
    </ADN> 
    <ADN> 
     <GID>1</GID> 
     <ID>1000</ID> 
     <Name>other name 1000</Name> 
    </ADN> 
</ArrayOfADN> 

  • ADN/GID戻り0 GID = 1
  • のハンドラ!
  • 他のハンドラがまだ呼び出されているのはなぜですか?
  • 期待される出力には'20' => ...が含まれていません。
  • 不要なノードを正しくスキップするにはどうすればよいですか?
+0

@toolicをドキュメントによると、_Handlersが固定order_でトリガされているので、おそらく私は順序が決定される方法を理解していません - aka、上記を解決する方法...;) – cajwine

+0

問題は、ハンドヘーダーが特定の要素に対して一定の順序でトリガーすることです。彼らはそれぞれ別のものにリセットします。 – Sobrique

答えて

4

「ゼロを返す」というのは、この文脈では赤いひねりのビットです。あなたの要素に複数のマッチがあった場合は、のうちの1つがでゼロを返すと、他のものは禁止されます。

これは、後続のノードをまだ試して処理しているわけではありません。

あなたはあなたの<ADN>要素の別々のサブ要素用のハンドラを持っていて、それらは別々にトリガするのは混乱していると思います。それは設計によるものです。 xpathの優先順位はありますが、重複する一致の場合のみです。あなたのものは完全に別々のものなので、彼らはさまざまな要素でトリガするので、それらはすべて「火」です。

しかし、あなたはそれが役に立つ知っているかもしれません - twig_handlersxpath表現することができます - あなたは明示的に言うことができる:

#!/usr/bin/env perl 
use strict; 
use warnings; 

use XML::Twig; 
my $twig = XML::Twig->parse(\*DATA); 
$twig -> set_pretty_print('indented_a'); 

foreach my $ADN ($twig -> findnodes('//ADN/GID[string()="1"]/..')) { 
    $ADN -> print; 
} 

これもtwig_handlers構文で動作します。ハンドラを行うことは、XMLを前処理する必要がある場合、またはメモリが制限されている場合にのみ、本当に便利であることをお勧めします。 20,000ノードの場合、あなたはそうかもしれません。 (その時点でpurgeはあなたの友人です)。

#!/usr/bin/env perl 
use strict; 
use warnings; 

use XML::Twig; 
my $twig = XML::Twig->new(
    pretty_print => 'indented_a', 
    twig_handlers => { 
     '//ADN[string(GID)="1"]' => sub { $_->print } 
    } 
); 

$twig->parse(\*DATA); 


__DATA__ 
<ArrayOfADN> 
    <ADN> 
     <GID>1</GID> 
     <ID>1</ID> 
     <Name>name 1</Name> 
    </ADN> 
    <ADN> 
     <GID>2</GID> 
     <ID>20</ID> 
     <Name>should be skipped because GID != 1</Name> 
    </ADN> 
    <ADN> 
     <GID>1</GID> 
     <ID>1000</ID> 
     <Name>other name 1000</Name> 
    </ADN> 
</ArrayOfADN> 

私はおそらくだけではなく、このようにそれを行うだろう、けれども:

#!/usr/bin/env perl 
use strict; 
use warnings; 

use XML::Twig; 

sub process_ADN { 
    my ($twig, $ADN) = @_; 
    return unless $ADN -> first_child_text('GID') == 1; 
    print "ADN with name:", $ADN -> first_child_text('Name')," Found\n"; 
} 


my $twig = XML::Twig->new(
    pretty_print => 'indented_a', 
    twig_handlers => { 
     'ADN' => \&process_ADN 
    } 
); 

$twig->parse(\*DATA); 


__DATA__ 
<ArrayOfADN> 
    <ADN> 
     <GID>1</GID> 
     <ID>1</ID> 
     <Name>name 1</Name> 
    </ADN> 
    <ADN> 
     <GID>2</GID> 
     <ID>20</ID> 
     <Name>should be skipped because GID != 1</Name> 
    </ADN> 
    <ADN> 
     <GID>1</GID> 
     <ID>1000</ID> 
     <Name>other name 1000</Name> 
    </ADN> 
</ArrayOfADN> 
関連する問題