首页 > 解决方案 > python svg 使用 minidom/etree/lxml 解析

问题描述

使用 python 我尝试使用 minidom/etree/lxml 解析 svg(xml 格式),我有以下 svg 文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:shaper="http://www.shapertools.com/namespaces/shaper"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="5319.4434mm"
   height="6025.5mm"
   viewBox="0 0 5319.4434 6025.5"
   version="1.1"
   id="svg1217"
   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
   sodipodi:docname="test.svg">
  <defs
     id="defs1211" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.0875"
     inkscape:cx="2965.7333"
     inkscape:cy="12836.281"
     inkscape:document-units="mm"
     inkscape:current-layer="layer2"
     showgrid="false"
     fit-margin-top="0"
     fit-margin-left="0"
     fit-margin-right="0"
     fit-margin-bottom="0"
     inkscape:window-width="1920"
     inkscape:window-height="1017"
     inkscape:window-x="-8"
     inkscape:window-y="-8"
     inkscape:window-maximized="1" />
  <metadata
     id="metadata1214">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:groupmode="layer"
     id="layer2"
     inkscape:label="Second_Layer"
     style="display:inline">
    <rect
       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;opacity:1"
       id="rect2567"
       width="1233.7142"
       height="1644.9524"
       x="459.61902"
       y="268.1666" />
  </g>
  <g
     inkscape:label="First_Layer"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(2594.7098,2684.756)"
     style="display:none">
    <g
       transform="matrix(10,0,0,10,-2594.7098,-2684.756)"
       id="Body_Körper116">
      <path
         style="vector-effect:non-scaling-stroke;fill:#000000"
         inkscape:connector-curvature="0"
         d="M 241.25,-479.9 V -500 h 17.5 v 20.1 z"
         shaper:cutDepth="0.0001105"
         shaper:pathType="exterior"
         transform="matrix(1,0,0,-1,-42.65,18.6)"
         id="path2" />
    </g>
    <g
       transform="matrix(10,0,0,10,-2594.7098,-2684.756)"
       id="Body_Körper114">
      <path
         style="vector-effect:non-scaling-stroke;fill:#000000"
         inkscape:connector-curvature="0"
         d="M 141.95,-480.1 V -500 h 16.1 v 19.9 z"
         shaper:cutDepth="0.0001103"
         shaper:pathType="exterior"
         transform="matrix(1,0,0,-1,-42.65,18.6)"
         id="path5" />
    </g>

其中包括 2 层(第 1 层和第 2 层),每层中有一些主体并分组。我想要做的是对这些物体执行操作(例如变换)以移动它们等。

我尝试了 minidom 和 etree,但在我的情况下,我无法清楚地了解这些树是如何构建和访问的。因此我有几个问题,希望有更多经验的人可以帮助我快速上轨道:)

  1. 使用时:

    lxml = ET.parse('test.svg') svgdoc = lxml.getroot()

或者

svgdoc = xml.dom.minidom.parse('test.svg')

我设法将文件读入树中。有人能告诉我如何在上面的例子中访问每棵树、子树、属性等吗?期待像“svgdoc.parent[1].child[1].属性通过树及其节点,但我得到了很多错误。

  1. 例如,我将如何访问带有“id="Body_Körper114" 的 Body 的 "transform="matrix(10,0,0,10,-2​​594.7098,-2684.756)" 以及如何访问 "shaper:cutDepth="0.0001105"嵌套在 Body_Körper114 中?

  2. 我可以阅读它们, path_d_strings = [path.getAttribute('d') for path in svgdoc.getElementsByTagName('path')] 但如果我想根据其中找到的某些条件更改嵌套在路径内(但直接在上面)的变换,那么如果我使用 getElementsByTagName-Method,我最终会得到更多“变换”元素,如“ shaper:cutDepth" as "transform" 不仅出现在 path 作为 "shaper:cut..." 中,而且出现在上面的 body 描述中,因此我不能简单地按索引浏览列表并应用更改。

  3. 我还觉得奇怪的是,我将 svgdoc 中的元素读取到其他一些列表中,在此列表中进行更改,然后在写入更改的同时写入 xml 文件。

path = svgdoc.getElementsByTagName("path")
    firstchild = path[0]
    firstchild.attributes["d"].value = "test"
    f = open('test2.svg', 'w')
    f.write(doc.toxml())
    doc.unlink()

我本来希望在保存之前必须将我通过 getElements 提取的列表传输回 svgdoc。这种结构是如何工作的?

  1. 使用 Inkscape,我可以删除所有变换部分并将所有内容置于绝对坐标。当我需要转换身体并用我的脚本移动它们时,我需要插入一个新的“节点”?!?在路径下(如“style”或“inkscape”)并将其保存到 xml 文件中。我将如何管理这个?

很抱歉这篇长文,但这真的让我很烦恼,我试图了解发生了什么。我阅读了教程、文档、示例,但没有真正解释如何控制这个结构。此外,我是 python 新手,仍然需要了解语法(不幸的是没有太多时间,因为我有 2 个小孩)

感谢您的帮助,非常感谢!干杯,

托比

标签: pythonparsingsvgminidomxml.etree

解决方案


你的帖子太长了,我看不懂。这是一个给你的例子。不知道能不能满足你的需求。如果您有任何问题,请留言。

from simplified_scrapy import SimplifiedDoc,req,utils

html = utils.getFileContent('test.svg')
doc = SimplifiedDoc(html)
path = doc.getElement('path') # Select element
path.setAttr('d','test') # Edit attribute
while True:
  path = doc.getElement('path',start=path._end)
  if not path: break
  path.setAttr('d','test2')
utils.saveFile('test2.svg', doc.html)

推荐阅读