2

输入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>

蟒蛇代码:

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 文件的确切副本。请在这方面帮助我。

4

2 回答 2

5

W3 定义了一个规范的 XML 标准。以这种格式编写的文档可以由任何符合 C14N 的工具链忠实地往返。

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

  • 将您的原始输入文档转换为 C14N 形式。
  • 使用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"?>行),您将不符合 C14N 标准。因此,这是您绝对不应该做的事情。如果你真的,真的想做这个错误的事情......

  • 不。
  • 但如果你必须这样做,你会这样做:

    outfile = open('output1.xml', 'w')
    outfile.write('<?xml version="1.0"?>\n')
    tree.write_c14n(outfile)
    outfile.close()
    
于 2013-07-26T15:16:45.443 回答
2

文档页面中,可以像这样添加 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 处理文件时,可能没有简单的方法可以完成这项工作。如果您想对文件进行细微更改,您可能最好使用lxml C14N支持。


命名空间前缀在 ElementTree 中默认更改。为了防止这种行为,您可以切换到默认情况下似乎保留命名空间前缀的lxml :

因为 etree 建立在 libxml2 之上,它是命名空间前缀感知的,所以 etree 保留命名空间声明和前缀,而 ElementTree 倾向于提出自己的前缀(ns0、ns1 等)。然而,当没有给出命名空间前缀时,etree 也会创建 ElementTree 样式前缀。

在任何情况下切换到 lxml 都是一个好主意,但是如果在另一端读取文件的程序足够兼容 XML,那么您观察到的更改应该不是问题。不幸的是,许多 XPath 处理器在命名空间前缀更改方面存在问题......

于 2013-07-26T15:42:36.460 回答