关于xml:lxml隐藏根标记的’xmlns’属性

lxml hiding 'xmlns' attribute of root tag

(在我问我的问题之前,请先讲一下下面的小故事!)

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

1
2
3
4
<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时,浏览器将显示以下错误消息:

This XML file does not appear to have any style information associated with it. The document tree is shown below. [...]

经过一些实验,我发现罪魁祸首是缺少的" xmlns"标签。 (我猜MathJax在具有此标签的页面中将另一个SVG放在更高的位置,因此在网页内部,无需再次重复它。等等。)即,将开始标签更改为此允许SVG在浏览器中单独显示:

1
2
3
4
<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是文档的根标记),我无法测试'xmlns'属性是否已经存在,实际上,如果我在同一文件上运行两次脚本,则会导致两个单独的标记被添加,这反过来导致lxml报错并崩溃。

因此:(i)为什么lxml对我隐藏某些属性,并且(ii)不管为什么我只能在xmlns标记不存在的情况下才添加它? (当然,我可以手动解析文件,但是我想要一个使用lxml的独立解决方案。)


我已经混合了两个关于名称空间的答案。 一个来自lxml:将名称空间添加到输入文件,另一个来自通过在python中使用lxml添加xml前缀声明。 第一个答案不涉及复制属性,因此我从第二个答案中借用了它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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可以处理这种任务。