使用lxml修改给定xml文档中的命名空间

时间:2014-01-06 09:48:54

标签: python xml lxml

我有一个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?

谢谢!

丹尼斯

1 个答案:

答案 0 :(得分:-2)

  

我想做的就是将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[:]

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