在 lxml 中使用命名空间

Using namespaces in lxml

我正在尝试使用 lxml 进行 svg 解析并与命名空间作斗争。

问题:

  1. 如何使用 tree.iterfind 和名称空间映射遍历所有 image 标签? tree.iterfind('image', root.nsmap) 不重新调整任何东西,更丑陋的 tree.iter('{http://www.w3.org/2000/svg}image') 有效
  2. 我正在尝试将 image 标签转换为 use 标签。虽然 lxml 给了我一个带有 xlinx:href 的属性字典,但它在将它传递给 makeelement 时会窒息,有没有优雅的解决方案?
  3. 我应该使用 lxml 还是有更好的(更直接的)?我的目标是将 image 标签重写为 use 标签并将引用的 svgs 的内容嵌入到符号中。 (到目前为止 lxml 我对命名空间的问题似乎令人厌恶)。

.

from lxml import etree

def inlineSvg(path):
    parser = etree.XMLParser(recover=True)
    tree = etree.parse(path, parser)

    root = tree.getroot()
    print(root.nsmap)


    for img in tree.iter('{http://www.w3.org/2000/svg}image'):
    #for img in tree.iterfind('image', root.nsmap): #for some reason I can't get this to work...
        print(img)

        #we have to translate xlink: to {http://www.w3.org/1999/xlink} for it to work, despit the lib returning xlink: ...
        settableAttributes = dict(img.items()) #img.attribute
        settableAttributes['{http://www.w3.org/1999/xlink}href'] = settableAttributes['xlink:href']
        del settableAttributes['xlink:href']

        print(etree.tostring(img.makeelement('use', settableAttributes)))
  • How do I iterate over all image tags, with tree.iterfind and a namsepace map?
for img in root.iterfind('image', namespaces=root.nsmap):
  • I am trying to turn image tags into use tags. While lxml gives me an attribute dictionary with xlinx:href it chokes on passing this to makeelement is there an elegant solution?

这些都适合我:

img.makeelement('use', dict(img.items())
img.makeelement('use', img.attrib)
  • Should I use lxml or is there something better (more straight forward)?

每个人都有意见。我喜欢 lxml。我觉得很简单。您的意见可能不同。


完整的程序:

from lxml import etree

def inlineSvg(path):
    parser = etree.XMLParser(recover=True)
    tree = etree.parse(path, parser)

    root = tree.getroot()

    for img in root.iterfind('image', namespaces=root.nsmap):
        use = img.makeelement('use', img.attrib, nsmap=root.nsmap)
        print(etree.tostring(use))

inlineSvg('xx.svg')

输入文件(xx.svg):

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">

  <rect x="10" y="10" height="130" width="500" style="fill: #000000"/>

  <image x="20" y="20" width="300" height="80"
     xlink:href="http://jenkov.com/images/layout/top-bar-logo.png" />

  <line x1="25" y1="80" x2="350" y2="80"
            style="stroke: #ffffff; stroke-width: 3;"/>
</svg>

结果:

$ python xx.py 
b'<use xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" height="80" width="300" x="20" y="20" xlink:href="http://jenkov.com/images/layout/top-bar-logo.png"/>'

参考: