2012-04-20 14 views
0

私はXML :: SAXを使ってXHTML文書の一部を修正しようとしていますが、すべての試みは失敗しました。ここでPerl XML :: SAXを使ってXML文書を変更する

は私がやろうとしているものです:

#!/usr/bin/perl 
package MyHandler; 
use strict; 
use warnings; 

use base qw(XML::SAX::Base); 
use Data::Dumper; 

sub start_element { 
    my $self = shift; 
    my $data = shift; 

    if($data->{LocalName} eq 'span') { 
     $data->{LocalName} = 'naps'; 
    } 

    $self->SUPER::start_element($data); # GOOD (and easy) ! 
    #print Dumper($data); 
} 

1; 

#============================ 
#Main programm 
#============================ 
use strict; 
use warnings; 

use XML::SAX::ParserFactory; 
use XML::SAX::Writer; 

my $out; 

my $o = XML::SAX::Writer->new(Output => \$out); 
my $h = MyHandler->new(Handler => $o); 
my $p = XML::SAX::ParserFactory->parser(Handler => $h); 

my $data; 
{ local undef $/ }; $data = <DATA>; 
$p->parse_string($data); 
print $out; 


__DATA__ 
<?xml version="1.0" encoding="UTF-8"?> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> 
<body> 
<wicket:panel> 
    <form wicket:id="mvpForm"> 
     <span>Edit Information: </span> 
     <input type="checkbox" wicket:id="editForm"/> 

     <span>Name: </span> 
     <span wicket:id="name"></span> 
     <input type="text" wicket:id="nameEdit"/> 

     <span>Last Name: </span> 
     <span wicket:id="lastName"></span> 
     <input type="text" wicket:id="lastNameEdit"/> 

     <span>DOB: </span> 
     <span wicket:id="dob"></span> 
     <input type="text" wicket:id="dobEdit"/> 


     <span>Occupation: </span> 
     <span wicket:id="occupation"></span> 
     <input type="text" wicket:id="occupationEdit"/> 


     <span>Gender: </span> 
     <span wicket:id="gender"></span> 
     <span wicket:id="genderEdit"/> 

     <input type="submit" wicket:id="submit"/> 

    </form> 
</wicket:panel> 
</body> 
</html> 

基本的な考え方は、「昼寝」にすべての「スパン」に変更し、STDOUTに得られた変性XMLを書くことです。

また、SAXを使用してXMLチャンクをマージできるかどうか、つまり別のものに展開された特定の要素が見つかった場合、どのように出力にマージすることができますかSTDOUT?

など。 から:

<xmltag> 
    <expandable/> 
</xmltag> 

へ:

<xmltag> 
    <expanded> 
     This is an expanded element 
    </expanded> 
</xmltag> 

感謝。

答えて

1

は、ここではサックスでそれを行う方法についての抜粋です:

#!/usr/bin/perl 
package MyHandler; 
use strict; 
use warnings; 

use base qw(XML::SAX::Base); 
use Data::Dumper; 

use XML::SAX::ParserFactory; 
use XML::SAX::Writer; 

sub start_element { 
    my $self = shift; 
    my $data = shift; 

    if($data->{LocalName} eq 'expand') { 
     $self->{in_include}++; 
     my $p = XML::SAX::ParserFactory->parser(Handler => $self); 
     $p->parse_string("<expanded>This is my expanded tag</expanded>"); 
     return; 
    } 

    #$data->{Attributes} = undef; 
    $self->SUPER::start_element($data); 
    #print Dumper($data); 
} 

sub characters { 
    my $self = shift; 
    my $data = shift; 

    #print "Data is $data->{Data}" if defined $data->{Data}; 
    $self->SUPER::characters($data); 
} 

sub end_element { 
    my ($self, $element) = @_; 
    if ($element->{LocalName} eq "expand") { 
     $self->{in_include}--; 
    } else { 
     $self->SUPER::end_element($element); 
    } 
} 

sub start_document { # same for end_document 
    my($self, $data) = @_; 
    return if($self->{in_include}); 
    $self->SUPER::start_document($data); 
} 

sub end_document { # same for end_document 
    my($self, $data) = @_; 
    return if($self->{in_include}); 
    $self->SUPER::end_document($data); 
} 

1; 

#============================ 
#Main programm 
#============================ 
use strict; 
use warnings; 

use XML::SAX::ParserFactory; 
use XML::SAX::Writer; 

my $out; 

my $o = XML::SAX::Writer->new(Output => \$out); 
my $h = MyHandler->new(Handler => $o); 
my $p = XML::SAX::ParserFactory->parser(Handler => $h); 

my $data; 
{ local undef $/ }; $data = <DATA>; 
$p->parse_string($data); 
print $out; 


__DATA__ 
<?xml version="1.0" encoding="UTF-8"?> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> 
<body> 
<wicket:panel> 
    <form wicket:id="mvpForm"> 
     <span>Edit Information: </span> 
     <input type="checkbox" wicket:id="editForm"/> 

     <span>Name: </span> 
     <span wicket:id="name"></span> 
     <input type="text" wicket:id="nameEdit"/> 

     <span>Last Name: </span> 
     <span wicket:id="lastName"></span> 
     <input type="text" wicket:id="lastNameEdit"/> 

     <span>DOB: </span> 
     <span wicket:id="dob"></span> 
     <input type="text" wicket:id="dobEdit"/> 

     <span>Occupation: </span> 
     <span wicket:id="occupation"></span> 
     <input type="text" wicket:id="occupationEdit"/> 

     <span>Gender: </span> 
     <span wicket:id="gender"></span> 
     <span wicket:id="genderEdit"/> 

     <input type="submit" wicket:id="submit"/> 

     <expand/> 

    </form> 
</wicket:panel> 
</body> 
</html> 

<expand/>タグが<expanded>This is my expanded tag</expanded>によって置き換えられます。

新しいパーサーを作成して解析するファイル/文字列を渡すことが基本的に必要です。しかし、いくつかの問題があることに注意してください。最初の1つは、拡張するタグをインターセプトしたイベントの伝播を停止することです。言い換えれば、$ self-> SUPER :: start/end_elementをタグの展開/入れ子にすると、置換されたタグが出力に終わらないようになります。

がプッシュコンテキストを/ usr/shareで/ perl5の/ XML/NamespaceSupportはせずにコンテキストをポップしようとすると:第二に、そうでない場合は、次のエラーが生成される、START_DOCUMENT/END_DOCUMENTをインターセプトし、それらのもののために親を呼び出すスキップするために必要です.pm 79行、チャンク1。

このメッセージはXMLためにトリガされている:: NamespaceSupportははSTART_DOCUMENTイベントにいくつかの初期化とEND_DOCUMENTイベントにいくつかのクリーンアップを行います。一部に障害が発生したクリーンアップ言い換えれば

問題は、コードでは、メイン文書用のこれらのイベントのペアと、インクルードされた各ドキュメント用のネストされたペアが存在することです。 2番目のend_documentイベントが発生すると、クリーンアップするものは存在しません。したがって、メッセージです。 Taken from here

1

キーなくたLocalNameからライターピック要素名のように思えます。代わりに変更するのではなくLocalNameに希望の結果を変更します。

if($data->{LocalName} eq 'span') { 
    $data->{LocalName} = 'naps'; 
} 

SAX

if($data->{LocalName} eq 'span') { 
    $data->{Name} = 'naps'; 
} 
+0

何そのテキストノードを追加することについてはどうですか? – daxim

+0

SAXはノードの追加をサポートしているとは思いません。恐らく汚い道を使っているでしょう! – tuxuday

+0

ありがとう、それは少し予期しなかったthoだった:)。はい、展開可能なノードが見つかると別のサックスパーサーを作成するのが最善の方法ですが、メインのパイプラインとどのようにマージするのですか?私はもう少し実験しますが、結局は解決策があるかもしれません。 – dryajov

2

への変更は、このような些細な変更のための最高のツールではありません。 DOMの実装を考えてみましょう。ここで

use strictures; 
use XML::LibXML qw(); 
my $dom = XML::LibXML->load_xml(…); 

for my $e ($dom->findnodes('//*')) { 
    $e->setNodeName('naps') if 'span' eq $e->nodeName; 
    if ('expandable' eq $e->nodeName) { 
     $e->setNodeName('expanded'); 
     $e->appendText('This is an expanded element'); 
    } 
} 
print $dom->toString; # ->toFile 
+0

ありがとう、これも動作します、唯一のconsernはどのようにメモリが集中するかです。 – dryajov

2

は、私はSAXよりも使いやすく見つけるXML::Twigベースのソリューションであり、(その後私が偏っ少しかもしれません; - )。 1 span(またはexpandable)要素だけがメモリに保持されるので、非常にメモリ効率が良いです。要素を拡大/マージについての自分の質問に答えるために

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

XML::Twig->new(twig_roots => { span  => sub { $_->set_tag('naps')->flush; }, 
           expandable => sub { XML::Twig::Elt->new(expanded => 'this is an expanded element')->print; }, 
           }, 
       twig_print_outside_roots => 1, 
      ) 
      ->parsefile(\*DATA); 
__DATA__ 
<?xml version="1.0" encoding="UTF-8"?> 
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> 
<body> 
<wicket:panel> 
    <form wicket:id="mvpForm"> 
     <span>Edit Information: </span> 
     <input type="checkbox" wicket:id="editForm"/> 

     <span>Name: </span> 
     <span wicket:id="name"></span> 
     <input type="text" wicket:id="nameEdit"/> 

     <span>Last Name: </span> 
     <span wicket:id="lastName"></span> 
     <input type="text" wicket:id="lastNameEdit"/> 

     <span>DOB: </span> 
     <span wicket:id="dob"></span> 
     <input type="text" wicket:id="dobEdit"/> 


     <span>Occupation: </span> 
     <span wicket:id="occupation"></span> 
     <input type="text" wicket:id="occupationEdit"/> 


     <span>Gender: </span> 
     <span wicket:id="gender"></span> 
     <span wicket:id="genderEdit"/> 

     <input type="submit" wicket:id="submit"/> 

    </form> 

<xmltag> 
    <expandable/> 
</xmltag> 

</wicket:panel> 
</body> 
</html> 
+0

+1簡単に簡単に – daxim

+0

少なくともモジュールのユーザーのために - ) – mirod

+0

かなり簡単で便利に見えます。私はdom/treeベースの解決策から遠ざかるようにしましたが、通常はメモリを集中的に使用していましたが、twigはDOMの利便性とサックスの明度のバランスが良いです。ありがとう! – dryajov

関連する問題