用Python替换SVG的内部内容

6 投票
4 回答
6001 浏览
提问于 2025-04-18 13:10

我有一个SVG模板,我正在复制并自定义它,以便为一个游戏制作几种不同的卡片和图块。我想用程序的方式(最好是用Python)来逐个卡片地更改模板中的元素。我发现有很多方法可以更改属性或CSS,但我找不到一个可以轻松解析现有SVG并替换元素的库。

我的模板的SVG大概长这样:

<!--Square 2" Tile Template -->
<svg xmlns="http://www.w3.org/2000/svg" width="181" height="181">
    <text id="tile_text" y="90" width="100%" 
          style="text-align:center;font-family:Verdana;font-size:20">
        TEXT TO REPLACE
    </text>
</svg>

我看过Python的lxmlxml.dom.minidom,但这两个似乎都不支持像tile_text_element.innerHTML = "新图块名称"这样的操作。谁能帮帮我?

补充一下我的工作流程,我正在为每张卡片创建一堆个性化的SVG,然后通过Inkscape批量渲染成PDF。

4 个回答

1

我觉得你可以用lxml这个库来实现,具体是通过Elementtext属性来操作的:

元素包含文本

>>> root = etree.Element("root")
>>> root.text = "TEXT"

>>> print(root.text)
TEXT

>>> etree.tostring(root)
b'<root>TEXT</root>'
1

你可以不使用Python来实现这个功能,svg支持参数

所以你可以使用:

<!--Square 2" Tile Template -->
<svg xmlns="http://www.w3.org/2000/svg" width="181" height="181">
    <text id="tile_text" y="90" width="100%" style="text-align:center;font-family:Verdana;font-size:20" content-value="param(label)">default</text>

然后使用:

your.svg?label=New Tile Name

需要注意的是,w3.org上的示例是通过模拟参数来实现的,因为并不是所有浏览器都支持这个功能。不过你可以使用他们的模拟方法,但他们提到不建议在正式环境中使用:

请注意,这些示例是通过一个Javascript原型模拟的。它应该在Opera、Firefox和Safari等浏览器中工作,可能在其他浏览器(比如Chrome?插件?)也能用。这个脚本可以直接使用,并且是根据CC许可证发布的,但并不适合用作正式代码。内容创作者被鼓励尝试这个代码,并根据经验向SVG工作组(www-svg@w3.org)提出建议和反馈。

2

另一种方法是使用lxml,这个方法似乎有效,但要注意,代码质量不太好:

$ cat card.py
#!/usr/bin/env python

from lxml import etree

with open('card.svg') as card:
    root = etree.fromstring(card.read())

root.find('.//{http://www.w3.org/2000/svg}text').text = "foobar"
print etree.tostring(root)
$ python card.py
<svg xmlns="http://www.w3.org/2000/svg" width="181" height="181">
    <text id="tile_text" y="90" width="100%" style="text-align:center;font-family:Verdana;font-size:20">foobar</text>
</svg>
1

你可以使用ETXPath或者普通的XPath,这里有一种可能的方法:

from lxml import etree

SVGNS = u"http://www.w3.org/2000/svg"
svg = '''<!--Square 2" Tile Template -->
<svg xmlns="http://www.w3.org/2000/svg" width="181" height="181">
    <text id="tile_text" y="90" width="100%" 
          style="text-align:center;font-family:Verdana;font-size:20">
        TEXT TO REPLACE
    </text>
</svg>'''

xml_data = etree.fromstring(svg)
# We search for element 'text' with id='tile_text' in SVG namespace
find_text = etree.ETXPath("//{%s}text[@id='tile_text']" % (SVGNS))
# find_text(xml_data) returns a list
# [<Element {http://www.w3.org/2000/svg}text at 0x106185ab8>]
# take the 1st element from the list, replace the text
find_text(xml_data)[0].text = 'BLAHBLAH'
new_svg = etree.tostring(xml_data)
print new_svg

然后就是结果。

<svg xmlns="http://www.w3.org/2000/svg" width="181" height="181">
    <text id="tile_text" y="90" width="100%" 
          style="text-align:center;font-family:Verdana;font-size:20">BLAHBLAH</text>
</svg>

希望这对你有帮助。

撰写回答