【问题标题】:Replacing inner contents of an SVG in Python在 Python 中替换 SVG 的内部内容
【发布时间】:2014-09-03 18:41:41
【问题描述】:

我有一个 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 = "New Tile Name" 之类的东西。帮忙?

编辑:

为了补充一点我的工作流程,我为每张卡片创建了一堆个性化的 svg,然后通过 inkscape 将它们批量渲染为 pdf。

【问题讨论】:

    标签: python xml dom svg


    【解决方案1】:

    另一种方法是使用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>
    

    【讨论】:

      【解决方案2】:

      您可以使用 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>
      

      希望对你有帮助。

      【讨论】:

        【解决方案3】:

        你可以在没有 Python 的情况下做到这一点,svg 支持parameters

        所以你可以使用

        <!--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 发表评论 WG 在 www-svg@w3.org 提出建议和批评 基于经验的规范。

        【讨论】:

        • 我在我的工作流程中添加了一些细节。我的目标是渲染出包含所有信息的 svg 文件,因为之后我正在运行批处理 pdf 渲染。我认为这不会起作用。
        【解决方案4】:

        我认为你可以在 lxml 中使用 textElement 属性:

        Elements contain text

        >>> root = etree.Element("root")
        >>> root.text = "TEXT"
        
        >>> print(root.text)
        TEXT
        
        >>> etree.tostring(root)
        b'<root>TEXT</root>'
        

        【讨论】:

          猜你喜欢
          • 2021-02-01
          • 1970-01-01
          • 2012-06-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-25
          • 2014-09-26
          • 1970-01-01
          相关资源
          最近更新 更多