将显式名称空间属性添加到特定xml标记

时间:2015-06-07 10:01:44

标签: xml perl xslt

在从一个程序(htlatex)生成的XML到另一个程序(ArborText Editor)的快速转换中,我需要替换以下形式的所有XML

<math xmlns="http://www.w3.org/1998/Math/MathML">
<mn>
....
</mn>
</math>

<m:math xmlns:m="http://www.w3.org/1998/Math/MathML">
<m:mn xmlns:m="http://www.w3.org/1998/Math/MathML">
....
</m:mn>
</m:math>

是否有更简洁的简单方法来实现这一目标,而不是搜索代码<math<mn>等并替换它们?或者这可以通过xslt完成吗?

1 个答案:

答案 0 :(得分:1)

免责声明:我将使用正则表达式!如果你害怕他们可能会得到你,请立即停止阅读。

因为这是一个非常有限的问题,我相信使用XML解析器来查找我们想要更改的内容然后使用正则表达式就可以了。我们不是试图用正则表达式解析任何东西,只是替换简单的文本模式。

我使用XML::Twig查找所有math个节点,将其XML作为字符串抓取,替换名称空间并将XML放回,这使得XML :: Twig解析更改后的字符串。如果正则表达式操作破坏了它无效的范围,我们会注意到这里因为解析会失败。

当然,假设math元素中没有其他名称空间。

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

my $xml = <<XML;
<container>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mn>
<foo>asdf</foo>
<bar>fdsa</bar>
</mn>
</math>
</container>
XML

my $t = XML::Twig->new(
    pretty_print  => 'indented',
    twig_handlers => {
        math => sub {
            my $new_xml = $_->outer_xml;
            $new_xml =~ s{ xmlns="http://www.w3.org/1998/Math/MathML"}{};
            $new_xml =~ s{<([a-zA-Z]+)}{<m:$1 xmlns:m="http://www.w3.org/1998/Math/MathML"}g;
            $new_xml =~ s{</}{</m:}g;

            $_->set_outer_xml($new_xml);
        },
    }
);
$t->parse($xml);
$t->print;

输出包含从math开始的每个元素中的命名空间。

<container>
  <m:math xmlns:m="http://www.w3.org/1998/Math/MathML">
    <m:mn xmlns:m="http://www.w3.org/1998/Math/MathML">
      <m:foo xmlns:m="http://www.w3.org/1998/Math/MathML">asdf</m:foo>
      <m:bar xmlns:m="http://www.w3.org/1998/Math/MathML">fdsa</m:bar>
    </m:mn>
  </m:math>
</container>

我确认它适用于更深层次的嵌套结构和多个math元素。