【问题标题】:Modify namespaces in a given xml document with lxml使用 lxml 修改给定 xml 文档中的命名空间
【发布时间】:2014-01-23 16:35:34
【问题描述】:

我有一个如下所示的 xml 文档:

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://someurl/Oldschema"
     xsi:schemaLocation="http://someurl/Oldschema Oldschema.xsd"
     xmlns:framework="http://someurl/Oldframework">
   <framework:tag1> ... </framework:tag1>
   <framework:tag2> <tagA> ... </tagA> </framwork:tag2>
</root>

我要做的就是将http://someurl/Oldschema 更改为http://someurl/Newschema 并将http://someurl/Oldframework 更改为http://someurl/Newframework 并保持其余文档不变。借助此线程lxml: add namespace to input file 的一些见解,我尝试了以下方法:

def fix_nsmap(nsmap, tag):
    """update the old nsmap-dict with the new schema-urls. Example:
    fix_nsmap({"framework": "http://someurl/Oldframework",
               None: "http://someurl/Oldschema"}) ==
      {"framework": "http://someurl/Newframework",
       None: "http://someurl/Newschema"}"""
    ...

from lxml import etree
root = etree.parse(XMLFILE).getroot()
root_tag = root.tag.split("}")[1]
nsmap = fix_nsmap(root.nsmap)
new_root = etree.Element(root_tag, nsmap=nsmap)
new_root[:] = root[:]
# ... fix xsi:schemaLocation
return etree.tostring(new_root, pretty_print=True, encoding="UTF-8",
    xml_declaration=True) 

这会在根标签中产生正确的“属性”,但对于文档的其余部分则完全失败:

<network xmlns:framework="http://someurl/Newframework"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://someurl/Newschema"
    xsi:schemaLocation="http://someurl/Newschema Schema.xsd">
<ns0:tag1 xmlns:ns0="http://someurl/Oldframework"> ... </ns0:information>
<ns1:tag2 xmlns:ns1="http://someurl/Oldframework"
          xmlns:ns2="http://someurl/Oldschema">
    <ns2:tagA> ... </ns2:tagA>
</ns1:tag2>

我的方法有什么问题?有没有其他方法可以更改命名空间?也许我可以使用 xslt?

谢谢!

丹尼斯

【问题讨论】:

标签: python xml lxml


【解决方案1】:

我要做的就是将http://someurl/Oldschema 更改为http://someurl/Newschema 并将http://someurl/Oldframework 更改为http://someurl/Newframework,并保持其余文档不变。

我会做一个简单的文本搜索和替换操作。这比摆弄 XML 节点要容易得多。像这样:

with open("input.xml", "r") as infile, open("output.xml", "w") as outfile:
    data = infile.read()
    data = data.replace("http://someurl/Oldschema", "http://someurl/Newschema")
    data = data.replace("http://someurl/Oldframework", "http://someurl/Newframework")
    outfile.write(data)

您受到启发的other question 是关于添加新命名空间(并保留旧命名空间)。但是您正在尝试修改现有的命名空间声明。在这种情况下,创建新的根元素并复制子节点不起作用。

这一行:

new_root[:] = root[:]

将原始根元素的子元素转换为新根元素的子元素。但是这些子节点仍然与旧的命名空间相关联。所以它们也必须被修改/重新创建。我想可能会想出一个合理的方法来做到这一点,但我认为你不需要它。文本搜索和替换就足够了,恕我直言。

【讨论】:

  • 这就是我现在“修复”这些文件的方法(使用 sed),但我希望会有一个更优雅的 python 解决方案。还是谢谢!
  • 只要命名空间映射不能改变(见bugs.launchpad.net/lxml/+bug/555602),我认为很难想出比旧的搜索和替换更紧凑或优雅的东西。
  • 如果反对者留下评论来解释这个答案有什么问题,那就太好了。
  • 我认为答案的问题在于它是硬编码的。没有人欣赏硬编码的东西。这是我对您的答案被否决的原因的看法。我也在研究这个问题,如果我发现一些通用的东西会告诉你。
  • @Rahul:我的回答可能不是很优雅,但可以完成工作。我能想到的唯一其他想法是使用 XSLT(请参阅 stackoverflow.com/a/51660868/407651stackoverflow.com/a/31870245/407651)。但我不确定这将如何减少“硬编码”。
猜你喜欢
  • 2012-10-10
  • 2018-06-03
  • 2010-10-22
  • 2012-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
相关资源
最近更新 更多