如何更改命名空间

时间:2011-07-14 14:32:08

标签: xml perl namespaces

如何使用perl将命名空间和uri更改为新的?文件很大(20 MB)并且包含一行,结构很复杂。 例如:

<?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>

3 个答案:

答案 0 :(得分: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 :(得分:3)

您可以通过此XSLT运行XML以转换为所需的输出:

<?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>

答案 2 :(得分:1)

进行全局替换很容易。假设您已将文件加载到一个长字符串中,以下代码将执行此替换:

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

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

正如您所说的文件相对较大,因此您可能必须实现流式传输方法。例如,您可以逐行读取文件。在阅读文件时,使用上面的方法转换每一行,然后写出临时文件。完成后,删除磁盘上的文件并重命名临时文件以替换它。