输入xml文件:
<?xml version="1.0"?>
<res:testcases xmlns:res="urn:testcases" id="a1e4bfdb-40a2-485c-a1ac-54d220056dd5" type="MODEL">
<mode>PRESSURE_CONTROL</mode>
<category>ADULT</category>
<testcase id="1" type="UNIQUE">
<parameter id="PEEP" value="1.0">true</parameter>
<parameter id="CMV_FREQ" value="4.0">true</parameter>
<parameter id="PRESS_ABOVE_PEEP" value="0.0">true</parameter>
<parameter id="I_E_RATIO" value="0.1">false</parameter>
</testcase>
</res:testcases>
Python代码:
import xml.etree.ElementTree as ET
tree = ET.parse('/home/AlAhAb65/Desktop/input.xml')
root = tree.getroot()
root.attrib['type'] = 'AVA'
tree.write('/home/AlAhAb65/Desktop/output1.xml')
输出xml文件:
<ns0:testcases id="a1e4bfdb-40a2-485c-a1ac-54d220056dd5" type="AVA" xmlns:ns0="urn:testcases">
<mode>PRESSURE_CONTROL</mode>
<category>ADULT</category>
<testcase id="1" type="UNIQUE">
<parameter id="PEEP" value="1.0">true</parameter>
<parameter id="CMV_FREQ" value="4.0">true</parameter>
<parameter id="PRESS_ABOVE_PEEP" value="0.0">true</parameter>
<parameter id="I_E_RATIO" value="0.1">false</parameter>
</testcase>
</ns0:testcases>
问题是当我复制并写入输出xml文件时3意外的事情发生了。它们如下: 1.输入xml文件的第一行自动删除 2.在第二行(输入中),文本'res'替换为'ns0'。关闭标签时也是如此 3.更改属性(第二行输入)的顺序。 但我想写(作为输出)我作为输入获得的xml文件的精确副本。请帮助我。
答案 0 :(得分:5)
W3定义了Canonical XML standard。以这种格式编写的文件可以通过任何符合C14N标准的工具链忠实地往返。
对于lxml.etree(具有C14N支持的ElementTree API的更强大的实现),这意味着您需要做两件事:
ElementTree.write_c14n()
调用生成输出文档。输入文件的C14N表单版本将如此(由xmlstarlet c14n
命令生成):
<res:testcases xmlns:res="urn:testcases" id="a1e4bfdb-40a2-485c-a1ac-54d220056dd5" type="MODEL">
<mode>PRESSURE_CONTROL</mode>
<category>ADULT</category>
<testcase id="1" type="UNIQUE">
<parameter id="PEEP" value="1.0">true</parameter>
<parameter id="CMV_FREQ" value="4.0">true</parameter>
<parameter id="PRESS_ABOVE_PEEP" value="0.0">true</parameter>
<parameter id="I_E_RATIO" value="0.1">false</parameter>
</testcase>
</res:testcases>
...以及适当修改的代码版本:
#!/usr/bin/env python
import lxml.etree
tree = lxml.etree.parse('input.xml')
root = tree.getroot()
root.attrib['type'] = 'AVA'
tree.write_c14n('output1.xml')
如果添加XML声明(<?xml version="1.0"?>
行), you will be noncomplaint with the C14N standard 。因此,这是你绝对不应该做的事情。如果你真的,真的想做错误的事......
但如果你必须这样做,你会这样做:
outfile = open('output1.xml', 'w')
outfile.write('<?xml version="1.0"?>\n')
tree.write_c14n(outfile)
outfile.close()
答案 1 :(得分:2)
从the documentation page开始,可以像这样添加XML声明:
tree.write('/home/AlAhAb65/Desktop/output1.xml', xml_declaration=True)
您还应该添加编码,因为默认编码是us-ascii:
tree.write('/home/AlAhAb65/Desktop/output1.xml', encoding='utf-8', xml_declaration=True)
或者您可以从原始文件中检索编码,但无论如何您将获得不同的XML声明,可能是这样的:
<?xml version="1.0" encoding="UTF-8"?>
或者您可以手动添加XML声明。无论如何,只要声明的编码与实际编码一致,轻微的声明不匹配就不应该成为任何健壮的XML解析器的问题。
XML中的属性顺序不重要,因此在API中解析文件时可能会丢失信息。在通过标准ElementTree API处理文件时,可能需要no simple way才能使其工作。如果您想对文件进行细微更改,最好还是必须使用lxml C14N支持。
在ElementTree中默认更改名称空间前缀。要防止出现这种情况,您可以切换到lxml,这似乎默认保留名称空间前缀:
因为etree是建立在libxml2之上的,它可以识别名称空间前缀,所以etree保留了名称空间声明和前缀,而ElementTree倾向于提出自己的前缀(ns0,ns1等)。但是,如果没有给出名称空间前缀,etree也会创建ElementTree样式前缀。
在任何情况下切换到lxml都是个好主意,但如果读取另一端文件的程序足够XML,那么您所观察到的更改应该不会成为问题。不幸的是,很多XPath处理器都存在名称空间前缀更改的问题......