Replacing inner contents of an SVG in Python

dom, python, svg, xml

Solution

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.

Problem

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.

Original source