【问题标题】:How to insert an attribute with the right namespace prefix using lxml如何使用 lxml 插入具有正确命名空间前缀的属性
【发布时间】:2020-03-09 00:18:00
【问题描述】:

有没有办法使用lxml 插入具有正确命名空间的 XML 属性?

例如,我想使用XLink 在 XML 文档中插入链接。我需要做的就是在某些元素中插入{http://www.w3.org/1999/xlink}href 属性。我想使用xlink前缀,但是lxml会生成像“ns0”、“ns1”这样的前缀……

这是我尝试过的:

from lxml import etree

#: Name (and namespace) of the *href* attribute use to insert links.
HREF_ATTR = etree.QName("http://www.w3.org/1999/xlink", "href").text

content = """\
<body>
<p>Link to <span>StackOverflow</span></p>
<p>Link to <span>Google</span></p>
</body>
"""

targets = ["https://stackoverflow.com", "https://www.google.fr"]
body_elem = etree.XML(content)
for span_elem, target in zip(body_elem.iter("span"), targets):
    span_elem.attrib[HREF_ATTR] = target

etree.dump(body_elem)

转储看起来像这样:

<body>
<p>link to <span xmlns:ns0="http://www.w3.org/1999/xlink"
                 ns0:href="https://stackoverflow.com">stackoverflow</span></p>
<p>link to <span xmlns:ns1="http://www.w3.org/1999/xlink"
                 ns1:href="https://www.google.fr">google</span></p>
</body>

我找到了一种通过在根元素中插入和删除属性来分解命名空间的方法,如下所示:

# trick to declare the XLink namespace globally (only one time).
body_elem = etree.XML(content)
body_elem.attrib[HREF_ATTR] = ""
del body_elem.attrib[HREF_ATTR]

targets = ["https://stackoverflow.com", "https://www.google.fr"]
for span_elem, target in zip(body_elem.iter("span"), targets):
    span_elem.attrib[HREF_ATTR] = target

etree.dump(body_elem)

这很丑,但它有效,我只需要做一次。我明白了:

<body xmlns:ns0="http://www.w3.org/1999/xlink">
<p>Link to <span ns0:href="https://stackoverflow.com">StackOverflow</span></p>
<p>Link to <span ns0:href="https://www.google.fr">Google</span></p>
</body>

但问题依然存在:如何将这个“ns0”前缀变成“xlink”?

【问题讨论】:

标签: python xml lxml xml-namespaces


【解决方案1】:

按照@mzjn 的建议使用register_namespace

etree.register_namespace("xlink", "http://www.w3.org/1999/xlink")

# trick to declare the XLink namespace globally (only one time).
body_elem = etree.XML(content)
body_elem.attrib[HREF_ATTR] = ""
del body_elem.attrib[HREF_ATTR]

targets = ["https://stackoverflow.com", "https://www.google.fr"]
for span_elem, target in zip(body_elem.iter("span"), targets):
    span_elem.attrib[HREF_ATTR] = target

etree.dump(body_elem)

结果如我所愿:

<body xmlns:xlink="http://www.w3.org/1999/xlink">
<p>Link to <span xlink:href="https://stackoverflow.com">StackOverflow</span></p>
<p>Link to <span xlink:href="https://www.google.fr">Google</span></p>
</body>

【讨论】:

  • 旁注:您可以使用cleanup_namespaces(),而不是在body 上创建和删除HREF_ATTR 来全局声明命名空间。示例:etree.cleanup_namespaces(body_elem, top_nsmap={"xlink": "http://www.w3.org/1999/xlink"})
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-14
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
相关资源
最近更新 更多