2011-07-07 7 views
4

私は、いくつかの子ノードのテキスト値が与えられたときに、XMLの特定のノードを削除するサブルーチンをPerlに書き込もうとしています。XML :: Twigで使用するXPath述語の修正

のようなXMLを考える:

<Path> 
    <To> 
    <My> 
     <Node> 
     <ChildA>ValA</ChildA> 
     <ChildB>ValB</ChildB> 
     <ChildC>ValC</ChildC> 
     </Node> 
    </My> 
    </To> 
</Path> 
<!-- A lot of siblings follow... --> 

私が使用しているXPath式が本質的である:私は私のスクリプトを実行しようとしているときに

/Path/To/My/Node[ChildA="ValA" and ChildB="ValB" and ChildC="ValC"] 

、私のようなエラーを取得しています:

Error in XPath expression 
/Path/To/My/Node[ChildA="ValA" and ChildB="ValB" and ChildC="ValC"] at 
ChildA="ValA" and ChildB="ValB" and ChildC="ValC" at Twig.pm line 3353 

私はこれに迷っていますし、提案を探しています。私は周りのグーグルで試してみましたが、私はXML::Twigのような述語を使用しようとしている実例を見つけることができません。問題が私のXPath構文にあるのか、どうして私がXML::Twigを使っているのか分かりません。良い測定のために

は、私も試してみた:

/Path/To/My/Node[ChildA/text()="ValA" and ChildB/text()="ValB" and ChildC/text()="ValC"] 

ものではありません運のいずれか。解決策は何ですか?あなたが言っているように、テストの中で

+0

あなたは 'findnodes'または' twig_handlers'ためのトリガとしてでこの表現を使用していますか? Seanが述べた 'findnodes'は、XML :: Twig :: XPathを使うならば、すべてのXPathを使うことができます。ハンドラをトリガするための述語はより限定されているので、子の値をテストする 'Node'のハンドラが必要です。 – mirod

答えて

3

Nodeは、コンテキストノードである:

/Path/To/My/Node[./ChildA="ValA" and ./ChildB="ValB" and ./ChildC="ValC"] 

これはXML::XPathを使用して、短いテストプログラムに私のために動作します。

EDIT:申し訳ありませんが、私はXML :: Twigについてよく知らないので、そのXPath機能について間違った前提を設定しました。ドキュメントによれば、それはあなたの例の複雑さのレベルまで上がらない "XPathのような"構文だけをサポートします。

my $twig = XML::Twig::XPath->new; 
$twig->parse('your string'); 
my $nodes = $twig->findnodes('/Path/To/My/Node[ChildA="ValA" and ChildB="ValB" and ChildC="ValC"]'); 
print $nodes; 

この版画 "ValAValBValC":あなたの代わりにXML::TwigXML::Twig::XPathを使用する場合は、あなたは完全なXPathエンジンを取得します。

+0

同じ種類のエラー。エラーは "./" – Dave

3

これを行うには2つの方法があります:XML全体を読み込んで不要なノードを削除してから、小枝を出力するか、やり直してフィルタリングします。これはもう少し複雑ですが、 。

最初の方法

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig::XPath; 

my $t= XML::Twig::XPath->new(pretty_print => 'indented') 
         ->parse(\*DATA); 
$_->delete for ($t->findnodes('/Path/To/My/Node[./ChildA="ValA" and ./ChildB="ValB" and ./ChildC="ValC"]')); 

$t->print; 

__DATA__ 
<Path> 
    <To> 
    <My> 
     <Node> 
     <ChildA>ValA</ChildA> 
     <ChildB>ValB</ChildB> 
     <ChildC>ValC</ChildC> 
     </Node> 
     <Node> 
     <ChildA>ValD</ChildA> 
     <ChildB>ValB</ChildB> 
     <ChildC>ValC</ChildC> 
     </Node> 
    </My> 
    </To> 
</Path> 
(あなたはXMLの最新バージョンを必要とするかもしれない:: XPathEngineを、私は古いもので、あるいはまたXPathエンジンとして動作することができるXML :: XPathの、でそれをテストしていません)

そして、「フィルタ」の方法:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

XML::Twig->new(twig_roots => { '/Path/To/My/Node' => \&filter }, 
       twig_print_outside_roots => 1, 
       keep_spaces => 1, 
      ) 
     ->parse(\*DATA); 
exit; 

# the handler expressions cannot lookahead, so we need to look at each node 
# once it's completely parsed 
sub filter 
    { my($t, $node)= @_; 
    if( ($node->field('ChildA') eq 'ValA') 
     && ($node->field('ChildB') eq 'ValB') 
     && ($node->field('ChildC') eq 'ValC') 
    ) 
     { $node->delete; } 
    else 
     { $t->flush; } 
    } 

__DATA__ 
<Path> 
    <To> 
    <My> 
     <Node> 
     <ChildA>ValA</ChildA> 
     <ChildB>ValB</ChildB> 
     <ChildC>ValC</ChildC> 
     </Node> 
     <Node> 
     <ChildA>ValD</ChildA> 
     <ChildB>ValB</ChildB> 
     <ChildC>ValC</ChildC> 
     </Node> 
    </My> 
    </To> 
</Path> 
関連する問題