更改XML对象的值

时间:2015-01-02 11:07:51

标签: xml perl svg

我是perl的新手,无法弄清楚如何解决这个问题。

我有一个变量,它包含一个XML形式的SVG图像。我需要更改SVG中tspan标记的值。

代码如下。

    my $tempSvgImage = 
qw~<?xml version="1.0" encoding="UTF-8" standalone="no" ?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="3200" height="3200" xml:space="preserve">
    <desc>Created with Fabric.js 1.4.0</desc>
    <defs></defs>
    <g transform="translate(482.36 1400) scale(8 8)">
        <text font-family="Arial, Helvetica, sans-serif" font-size="50" font-style="normal" font-weight="normal" text-decoration="none" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: #C9FA51; opacity: 1;" transform="translate(-40.3 49)">
            <tspan x="0" y="-32.5" fill="#C9FA51">SampleCode</tspan>
        </text>
    </g>
</svg>~

在上面的代码中,我需要将tspan代码的值从Sample Code更改为New value。我该怎么办呢?

1 个答案:

答案 0 :(得分:1)

来自XML :: Simple docs:

The use of this module in new code is discouraged.

2005年,perlmonks的XML :: LibXML教程的作者发布了:

Also, XML::XPath is buggy and no-longer maintained so I don't recommend that.

这是XML :: LibXML:

use strict;
use warnings;
use 5.016;
use XML::LibXML;


my $dom = XML::LibXML->load_xml(string => <<'END_OF_XML');
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="3200" height="3200" xml:space="preserve">
    <desc>Created with Fabric.js 1.4.0</desc>
    <defs></defs>
    <g transform="translate(482.36 1400) scale(8 8)">
        <text font-family="Arial, Helvetica, sans-serif" font-size="50" font-style="normal" font-weight="normal" text-decoration="none" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: #C9FA51; opacity: 1;" transform="translate(-40.3 49)">
            <tspan x="0" y="-32.5" fill="#C9FA51">SampleCode</tspan>
        </text>
    </g>
</svg>
END_OF_XML

#Deal with the namespace declared in the svg tag(explanation below):
my $xpc = XML::LibXML::XPathContext->new($dom); 
$xpc->registerNs('ns', 'http://www.w3.org/2000/svg');
my ($tspan) = $xpc->findnodes('//ns:tspan');

#Change the tspan's text:
$tspan->removeChildNodes();
$tspan->appendTextNode("New data");

#Prove that the tspan's text changed:
say $tspan; 
say $dom->toString;

svg标记内的所有元素都具有以下形式的名称:

http://www.w3.org/2000/svg:tspan
|<----- namespace ------>|:tag name

...因为这个指令:

<svg xmlns="http://www.w3.org/2000/svg"

这表示<svg>标记内的每个标记名称都以命名空间名称作为前缀:

 http://www.w3.org/2000/svg

所以tspan的名字实际上是:

<http://www.w3.org/2000/svg:tspan ...>

因为这样的名字太难以处理,你可以使用别名:

$xpc->registerNs('ns', 'http://www.w3.org/2000/svg');

然后perl代码中的tspan标记的名称变为:

ns:tspan

然而,XML :: LibXML解析器速度极慢 - 即使对于那个简短的XML文档(编辑:DOCTYPE以及慢速连接也是我的程序花了大约5秒钟完成的原因。删除DOCTYPE解决了这个问题)。所以,这里是XML :: Twig:

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

XML::Twig->new( 
    map_xmlns => {'http://www.w3.org/2000/svg' => "svg"},

    twig_handlers => { 
        'svg:text/svg:tspan' => sub { $_->set_text('New Stuff') } 
    },

    keep_original_prefix => 1,
    pretty_print => 'indented', 
)
->parse(<<'END_OF_XML')
<?xml version="1.0" encoding="UTF-8"?>
<my-root>
  <text>
    <tspan>Sample Code1</tspan>
  </text>

  <svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
      <desc>Created with Fabric.js 1.4.0</desc>
      <defs></defs>
      <g transform="translate(482.36 1400) scale(8 8)">
        <text font-family="Arial, Helvetica, sans-serif" font-size="50" font-style="normal" font-weight="normal" text-decoration="none" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: #C9FA51; opacity: 1;" transform="translate(-40.3 49)">
          <tspan x="0" y="-32.5" fill="#C9FA51">SampleCode2</tspan>
        </text>
      </g>
  </svg>
</my-root>
END_OF_XML
->print;