更改 XML 对象的值
Change value of an XML object
我是 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
。我应该怎么做?
来自 XML::Simple 文档:
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 ...>
因为这样的名字太难用了,你可以给 url:
添加别名
$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;
我是 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
。我应该怎么做?
来自 XML::Simple 文档:
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 ...>
因为这样的名字太难用了,你可以给 url:
添加别名$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;