复制输入xml文件并使用Python完全编写

时间:2013-07-26 14:57:48

标签: python xml

输入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文件的精确副本。请帮助我。

2 个答案:

答案 0 :(得分:5)

W3定义了Canonical XML standard。以这种格式编写的文件可以通过任何符合C14N标准的工具链忠实地往返。

对于lxml.etree(具有C14N支持的ElementTree API的更强大的实现),这意味着您需要做两件事:

输入文件的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处理器都存在名称空间前缀更改的问题......