escapecharacter
escapecharacter

Reputation: 965

Replacing inner contents of an SVG in Python

I have an svg template that I am copying and customizing to create several different cards and tiles for a game. I want to programmatically (in Python, preferably) change elements from the template per-card. I seem to have no trouble finding ways to change attributes or css, but I'm having trouble finding a library where I can easily parse an existing svg and replace elements.

The svg of my template looks somewhat like this:

<!--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>

I have looked at Python's lxml and xml.dom.minidom but neither of them seem to support something like tile_text_element.innerHTML = "New Tile Name". Help?

EDIT:

To add a little bit about my workflow, I am creating a bunch of individualized svgs for each card, then batch rendering them to pdf through inkscape.

Upvotes: 6

Views: 6483

Answers (4)

karlcow
karlcow

Reputation: 6972

You can do with ETXPath or just XPath, but here a possible way:

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

Then the result.

<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>

Hope it helps.

Upvotes: 1

Sergey
Sergey

Reputation: 12427

I think you can do it in lxml with text property of Element:

Elements contain text

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

>>> print(root.text)
TEXT

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

Upvotes: 1

Julien Palard
Julien Palard

Reputation: 11596

Another way is to use lxml, seems to work, WARNING bad quality code:

$ 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>

Upvotes: 2

Julien Palard
Julien Palard

Reputation: 11596

You can do this without Python, svg support parameters

So you may use

<!--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>

and use:

your.svg?label=New Tile Name

Note that the working example on w3.org emulates parameters, as not every browser seems to support it, but you can reuse their emulation, but they state you should not use it in production:

Note that these examples are emulated by a Javascript prototype. It should work in Opera, Firefox, and Safari, and maybe others (Chrome? Plugins?). The script may be used as is, and is released under a CC license, but it is not intended as production code. Content authors are encouraged to experiment with this code, and to comment to the SVG WG at [email protected] with suggestions and critiques of the specification based on experience.

Upvotes: 1

Related Questions