python - 更改 lxml 中的元素命名空间

标签 python xml lxml xml-namespaces elementtree

lxml ,我不确定如何正确删除现有元素的命名空间并设置一个新元素。

例如,我正在解析这个最小的 xml 文件:

<myroot xmlns="http://myxml.com/somevalue">
    <child1>blabla</child1>
    <child2>blablabla</child2>
</myroot>

......我希望它变成:
<myroot xmlns="http://myxml.com/newvalue">
    <child1>blabla/child1>
    <child2>blablabla</child2>
</myroot>

lxml :
from lxml import etree as ET
tree = ET.parse('myfile.xml')
root= tree.getroot()

如果我检查 root :
In [7]: root
Out[7]: <Element {http://myxml.com/somevalue}myroot at 0x7f6e13832588>
In [8]: root.nsmap
Out[8]: {None: 'http://myxml.com/somevalue'}
In [11]: root.tag
Out[11]: '{http://myxml.com/somevalue}myroot'

理想情况下,我想结束:
In [8]: root.nsmap
Out[8]: {None: 'http://myxml.com/newvalue'}
In [11]: root.tag
Out[11]: '{http://myxml.com/newvalue}myroot'

至于标签,只需设置正确的字符串即可。怎么样nsmap ?

最佳答案

我同意 mzjn 和 Parfait;我会使用 XSLT 来更改命名空间。

通过将新旧 namespace 作为参数传入,可以使 XSLT 具有相当的可重用性。

例子...

XML 输入 (输入.xml)

<myroot xmlns="http://myxml.com/somevalue">
    <child1>blabla</child1>
    <child2>blablabla</child2>
</myroot>

XSLT 1.0 (测试.xsl)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="orig_namespace"/>
  <xsl:param name="new_namespace"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*" priority="1">
    <xsl:choose>
      <xsl:when test="namespace-uri()=$orig_namespace">
        <xsl:element name="{name()}" namespace="{$new_namespace}">
          <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

python

from lxml import etree

tree = etree.parse("input.xml")
xslt = etree.parse("test.xsl")

orig_namespace = "http://myxml.com/somevalue"
new_namespace = "http://myxml.com/newvalue"

new_tree = tree.xslt(xslt, orig_namespace=f"'{orig_namespace}'",
                     new_namespace=f"'{new_namespace}'")
print(etree.tostring(new_tree, pretty_print=True).decode("utf-8"))

输出
<myroot xmlns="http://myxml.com/newvalue">
  <child1>blabla</child1>
  <child2>blablabla</child2>
</myroot>

此外,如果您使用以下输入(使用命名空间前缀)...

<ns1:myroot xmlns:ns1="http://myxml.com/somevalue">
    <ns1:child1>blabla</ns1:child1>
    <ns1:child2>blablabla</ns1:child2>
</ns1:myroot>

你得到这个输出...

<ns1:myroot xmlns:ns1="http://myxml.com/newvalue">
  <ns1:child1>blabla</ns1:child1>
  <ns1:child2>blablabla</ns1:child2>
</ns1:myroot>

https://lxml.de/xpathxslt.html有关在 lxml 中使用 XSLT 的更多信息。

关于python - 更改 lxml 中的元素命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51655130/

相关文章:

python - 了解tornado协程装饰器+twitter认证

python - subprocess.communicate() 不会向通过 git 调用 ssh 的 Popen 提供输入

java - "java.lang.IllegalArgumentException: No view found for id 0x7f090057 for fragment"- Android fragment

android - ProgressBar 间隙

python - 使用 LXML 返回标题文本

python - 如何在Python中出现异常后继续读取txt文件

python - 如果用户走错路线,如何使用 FastAPI 提供 404.html 页面?

sql - 在 SQL Server 的 XML 文档中查找节点顺序

python - 使用 lxml、xpath 在 Python 中解析 HTML

python - 在遍历 lxml 树时向节点添加深度