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