2011-07-14 9 views
3

名前空間とuriをperlで新しいものに変更するには?ファイルは大きく(20MB)、1行で構成されており、構造が複雑です。 例:名前空間を変更するには

<?xml version="1.0" encoding="utf-8"?> 
<m:sr xmlns:m="http://www.example.com/mmm" xml:lang="et"> 
<m:A m:AS="EX" m:KF="sss1"> 
<m:m m:u="uus" m:O="ggg">ggg</m:m> 
</m:A> 

</m:sr> 

へ:

<?xml version="1.0" encoding="utf-8"?> 
<a:sr xmlns:a="http://www.example.com/aaa" xml:lang="et"> 
<a:A a:AS="EX" a:KF="sss1"> 
<a:m a:u="uus" a:O="ggg">ggg</a:m> 
</a:A> 

</a:sr> 

答えて

4

これはXML :: Twigで行うことができます。

以下のコードは、入力に関する仮定が非常に少ないという点で非常にきれいです。特に、接頭辞ではなく入力の名前空間のURIに依存しています。小枝は、要素が解析されるたびにフラッシュされるため、メモリ内のデータはほとんど保持されません。

#!/usr/bin/perl 

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

# parameters, may be changed 
my $SR  = 'sr';       # local name of the root of the fragment 
my $OUT = 'a';       # prefix in the output 
my $IN_NS = 'http://www.example.com/mmm'; # namespace URIs 
my $OUT_NS = 'http://www.example.com/aaa'; 

my $t= XML::Twig->new( 
      map_xmlns => { $IN_NS => $OUT, $OUT_NS => $OUT, }, 
      start_tag_handlers => { "$OUT:$SR" => \&change_ns_decl, }, 
      twig_handlers => { _all_ => sub { $_->flush; }, }, 
      keep_spaces => 1, 
         ) 
        ->parse(\*DATA); # replace by parsefile("my.xml"); 

exit; 

sub change_ns_decl 
    { my($t, $sr)= @_; 
    $sr->set_att("xmlns:$OUT" => $OUT_NS); 
    } 

__DATA__ 
<?xml version="1.0" encoding="utf-8"?> 
<m:sr xml:lang="et" xmlns:m="http://www.example.com/mmm"> 
<m:A m:AS="EX" m:KF="sss1"> 
<m:m m:u="uus" m:O="ggg">ggg</m:m> 
</m:A> 
</m:sr> 
1

置き換えるグローバルを行うことは、容易に働くだろう。あなたはファイルが比較的大きく、したがって、あなたはストリーミング方式を実装する必要があります言ったように

my $current_namespace = "m"; 
my $new_namespace = "a"; 

$xml =~ s/\<$current_namespace:/\<$new_namespace:/g; 

:あなたは、1つの長い文字列に次のようにあなたのファイルをロードしたと仮定すると、この置換を行うだろう。たとえば、行ごとにファイルを読み込むことができます。ファイルを読むときに、上記の方法で各行を変換し、一時ファイルに書き出します。終了したら、ディスク上のファイルを削除し、一時ファイルの名前を変更して置き換えます。

+0

。私がそれを行ごとに読んだら、このメソッドはすばやくすべてのメモリを使います。 – Paxmees

+0

私が提案したのは、次の入力行を処理する前に各行を出力ファイルに書き込むことでした。これはすぐにメモリ不足になることはありません。 –

3

あなたは所望の出力に変換するために、このXSLTによってXMLを実行することができます:すべてのXMLが1行にあるよう

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:m="http://www.example.com/mmm" 
xmlns:a="http://www.example.com/aaa" 
exclude-result-prefixes="m"> 

<xsl:output indent="yes"/> 

    <!--identity template to copy content forward by default--> 
    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()" /> 
     </xsl:copy> 
    </xsl:template> 

    <!--Change any elements bound to the "m" namespace, to be in the "a" namespace--> 
    <xsl:template match="m:*"> 
     <xsl:element name="a:{local-name()}" > 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:element> 
    </xsl:template> 

    <!--Change any attributes bound to the "m" namespace, to be in the "a" namespace--> 
    <xsl:template match="@m:*"> 
     <xsl:attribute name="a:{local-name()}"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 

</xsl:stylesheet> 
関連する問題