lxml隐藏root <svg>标记

时间:2018-04-06 04:18:06

标签: xml svg lxml

(在我提出问题之前,请先跟下以下小故事吧!)

我有一些由MathJax生成的SVG元素,在生成后,看起来像是这样(在元素检查器中找到):

<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="6.768ex" height="2.468ex" viewBox="0 -825.2 2914.1 1062.4">
    <defs>...</defs>
    <g>...</g>
</svg>

当我尝试在chrome或safari中单独显示此SVG时,浏览器会显示以下错误消息:

  

此XML文件似乎没有与之关联的任何样式信息。文档树如下所示。 [...]

经过一些实验,我发现罪魁祸首是缺少'xmlns'标签。 (我猜MathJax在具有此标记的页面中放置了更高的SVG,因此在网页内部,不需要再次重复。或者某些东西。)即,更改开始<svg>标记为此,浏览器可以自行显示SVG:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="6.768ex" height="2.468ex" viewBox="0 -825.2 2914.1 1062.4">
    <defs>...</defs>
    <g>...</g>
</svg>

(请注意新的xmlns属性。)

行。好。

现在我想自动执行添加缺少的xmlns标记的任务。我想使用python lxml实用程序。

不幸的是(最终提出我的问题!),lxml似乎隐藏了以'xmlns'开头的所有属性,我不知道为什么。虽然它允许我添加'xmlns'属性(例如,通过执行

root.attrib['xmlns'] = "http://www.w3.org/2000/svg"

其中root是文档的根<svg>标记),我无法测试'xmlns'属性是否已经存在,实际上如果我在同一个文件上运行两次脚本这会导致添加两个单独的xmlns标记,从而导致lxml抱怨并崩溃。

所以:(i)为什么lxml会隐藏我的某些属性,以及(ii)无论如何,只有在xmlns标记不存在的情况下才能添加ENTER标记? (当然我可以手动解析文件,但我想要一个使用lxml的独立解决方案。)

1 个答案:

答案 0 :(得分:0)

我已经混合了两个关于命名空间的答案。一个来自lxml: add namespace to input file,另一个来自Adding xml prefix declaration with lxml in python。第一个答案不涉及复制属性,所以我从第二个答案中借用了它。

from lxml import etree
from io import StringIO, BytesIO

# excerpt from https://commons.wikimedia.org/wiki/File:SVG_logo.svg
# note that xmlns is omitted
xml = '<svg xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-50 -50 100 100"><rect id="background" x="-50" y="-50" width="100" height="100" rx="4" fill="#f90"/>  <g id="c">      <circle id="n" cy="-31.6" r="7.1" fill="#fff"/> </g></svg>'
tree = etree.parse(StringIO(xml))
root = tree.getroot()

nsmap = root.nsmap
nsmap[None] = 'http://www.w3.org/2000/svg'
root2 = etree.Element(root.tag, nsmap=nsmap)
root2[:] = root[:]
for a in root.attrib:
  root2.attrib[a] = root.attrib[a]

tree2 = etree.parse(StringIO(etree.tostring(root2, encoding="unicode")))
root3 = tree2.getroot()
print(root3)
# <Element {http://www.w3.org/2000/svg}svg at 0x58778f0>

print(root3.nsmap)
# {'xlink': 'http://www.w3.org/1999/xlink', None: 'http://www.w3.org/2000/svg'}

这对你有用,但我相信MathJax有办法处理这类任务。