Python: xml.etree.ElementTree 破坏 xml 格式
Python: xml.etree.ElementTree destroys xml format
我有一个格式为 XML.
的 ISM 文件(InstallShield 项目)
我需要更改文件中的一些属性,所以我使用了xml.etree.ElementTree(Python库)。
我可以找到这些值并更改它们,但是,在用更新的值保存文件后,我无法在 InstallShield 中打开它(我收到一个文件无法打开的一般错误)。
当我将旧文件与新文件进行比较时,我发现除了更改的值外,新文件中缺少一些行 XML 并且在某些行中标签名称已更改。
为什么会这样?除了我所做的更改之外,是否有任何事情可以使文件保持原样?我应该使用其他工具来进行更改吗?
例如,以下部分出现在原文中XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="is.xsl" ?>
<!DOCTYPE msi [
<!ELEMENT msi (summary,table*)>
<!ATTLIST msi version CDATA #REQUIRED>
<!ATTLIST msi xmlns:dt CDATA #IMPLIED
codepage CDATA #IMPLIED
compression (MSZIP|LZX|none) "LZX">
<!ELEMENT summary (codepage?,title?,subject?,author?,keywords?,comments?,
template,lastauthor?,revnumber,lastprinted?,
createdtm?,lastsavedtm?,pagecount,wordcount,
charcount?,appname?,security?)>
<!ELEMENT codepage (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT subject (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT keywords (#PCDATA)>
<!ELEMENT comments (#PCDATA)>
<!ELEMENT template (#PCDATA)>
<!ELEMENT lastauthor (#PCDATA)>
<!ELEMENT revnumber (#PCDATA)>
<!ELEMENT lastprinted (#PCDATA)>
<!ELEMENT createdtm (#PCDATA)>
<!ELEMENT lastsavedtm (#PCDATA)>
<!ELEMENT pagecount (#PCDATA)>
<!ELEMENT wordcount (#PCDATA)>
<!ELEMENT charcount (#PCDATA)>
<!ELEMENT appname (#PCDATA)>
<!ELEMENT security (#PCDATA)>
<!ELEMENT table (col+,row*)>
<!ATTLIST table
name CDATA #REQUIRED>
<!ELEMENT col (#PCDATA)>
<!ATTLIST col
key (yes|no) #IMPLIED
def CDATA #IMPLIED>
<!ELEMENT row (td+)>
<!ELEMENT td (#PCDATA)>
<!ATTLIST td
href CDATA #IMPLIED
dt:dt (string|bin.base64) #IMPLIED
md5 CDATA #IMPLIED>
]>
<msi version="2.0" xmlns:dt="urn:schemas-microsoft-com:datatypes" codepage="65001">
但在新的 XML 中它消失了,取而代之的只有:
<msi xmlns:ns0="urn:schemas-microsoft-com:datatypes" codepage="65001" version="2.0">
差异较多,这里只是举例
我用来进行更改的python代码是
tree = Et.parse(ism_file_path)
root = tree.getroot()
for attributes_group in root:
for attribute in attributes_group:
if attribute.tag == "revnumber":
new_package_code = increment_hex_number(attribute.text)
attribute.text = new_package_code
tree.write(ism_file_path)
谢谢!
最后我搬到了一个新图书馆 - lxml。
与 xml.etree.ElementTree
相反,这个库保留所有标签的顺序,所以我做了完全相同的事情并且它起作用了:
def modify_ism_file(ism_file_path):
context = etree.iterparse(ism_file_path)
for action, attributes_group in context:
for attribute in attributes_group:
if attribute.tag == "revnumber":
print "Found package code. TAG = {0} TEXT = {1}".format(attribute.tag, attribute.text)
new_package_code = increment_hex_number(attribute.text)
print "New package code is {0}".format(new_package_code)
attribute.text = new_package_code
obj_xml = etree.tostring(context.root, pretty_print=True, xml_declaration=True, encoding="utf-8")
with open(ism_file_path, "w") as f:
f.write(obj_xml)
首先,我想指出 InstallShield 有一个默认的编译器设置,即每次您构建 MSI 时都会生成一个新的 PackageCode。这是一个最佳实践,所以我真的不明白为什么你需要为这种情况编辑 ISM。
我要指出的第二件事是,ISM 的 RAW DTD XML 格式很难处理。我倾向于将 COM 自动化接口用于大多数动态创作,然后以二进制格式保存项目,这样我就可以像使用 ORCa 一样将其作为关系数据库进行编辑。 WiX C#/DTF 自定义操作具有 LINQ 支持,使这更容易做到。您甚至可以编写 C# 帮助器 class 并从 python 调用它。然后,您可以在自动化界面中打开它,并根据需要将其保存为 XML 格式。
我有一个格式为 XML.
的 ISM 文件(InstallShield 项目)我需要更改文件中的一些属性,所以我使用了xml.etree.ElementTree(Python库)。
我可以找到这些值并更改它们,但是,在用更新的值保存文件后,我无法在 InstallShield 中打开它(我收到一个文件无法打开的一般错误)。
当我将旧文件与新文件进行比较时,我发现除了更改的值外,新文件中缺少一些行 XML 并且在某些行中标签名称已更改。
为什么会这样?除了我所做的更改之外,是否有任何事情可以使文件保持原样?我应该使用其他工具来进行更改吗?
例如,以下部分出现在原文中XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="is.xsl" ?>
<!DOCTYPE msi [
<!ELEMENT msi (summary,table*)>
<!ATTLIST msi version CDATA #REQUIRED>
<!ATTLIST msi xmlns:dt CDATA #IMPLIED
codepage CDATA #IMPLIED
compression (MSZIP|LZX|none) "LZX">
<!ELEMENT summary (codepage?,title?,subject?,author?,keywords?,comments?,
template,lastauthor?,revnumber,lastprinted?,
createdtm?,lastsavedtm?,pagecount,wordcount,
charcount?,appname?,security?)>
<!ELEMENT codepage (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT subject (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT keywords (#PCDATA)>
<!ELEMENT comments (#PCDATA)>
<!ELEMENT template (#PCDATA)>
<!ELEMENT lastauthor (#PCDATA)>
<!ELEMENT revnumber (#PCDATA)>
<!ELEMENT lastprinted (#PCDATA)>
<!ELEMENT createdtm (#PCDATA)>
<!ELEMENT lastsavedtm (#PCDATA)>
<!ELEMENT pagecount (#PCDATA)>
<!ELEMENT wordcount (#PCDATA)>
<!ELEMENT charcount (#PCDATA)>
<!ELEMENT appname (#PCDATA)>
<!ELEMENT security (#PCDATA)>
<!ELEMENT table (col+,row*)>
<!ATTLIST table
name CDATA #REQUIRED>
<!ELEMENT col (#PCDATA)>
<!ATTLIST col
key (yes|no) #IMPLIED
def CDATA #IMPLIED>
<!ELEMENT row (td+)>
<!ELEMENT td (#PCDATA)>
<!ATTLIST td
href CDATA #IMPLIED
dt:dt (string|bin.base64) #IMPLIED
md5 CDATA #IMPLIED>
]>
<msi version="2.0" xmlns:dt="urn:schemas-microsoft-com:datatypes" codepage="65001">
但在新的 XML 中它消失了,取而代之的只有:
<msi xmlns:ns0="urn:schemas-microsoft-com:datatypes" codepage="65001" version="2.0">
差异较多,这里只是举例
我用来进行更改的python代码是
tree = Et.parse(ism_file_path)
root = tree.getroot()
for attributes_group in root:
for attribute in attributes_group:
if attribute.tag == "revnumber":
new_package_code = increment_hex_number(attribute.text)
attribute.text = new_package_code
tree.write(ism_file_path)
谢谢!
最后我搬到了一个新图书馆 - lxml。
与 xml.etree.ElementTree
相反,这个库保留所有标签的顺序,所以我做了完全相同的事情并且它起作用了:
def modify_ism_file(ism_file_path):
context = etree.iterparse(ism_file_path)
for action, attributes_group in context:
for attribute in attributes_group:
if attribute.tag == "revnumber":
print "Found package code. TAG = {0} TEXT = {1}".format(attribute.tag, attribute.text)
new_package_code = increment_hex_number(attribute.text)
print "New package code is {0}".format(new_package_code)
attribute.text = new_package_code
obj_xml = etree.tostring(context.root, pretty_print=True, xml_declaration=True, encoding="utf-8")
with open(ism_file_path, "w") as f:
f.write(obj_xml)
首先,我想指出 InstallShield 有一个默认的编译器设置,即每次您构建 MSI 时都会生成一个新的 PackageCode。这是一个最佳实践,所以我真的不明白为什么你需要为这种情况编辑 ISM。
我要指出的第二件事是,ISM 的 RAW DTD XML 格式很难处理。我倾向于将 COM 自动化接口用于大多数动态创作,然后以二进制格式保存项目,这样我就可以像使用 ORCa 一样将其作为关系数据库进行编辑。 WiX C#/DTF 自定义操作具有 LINQ 支持,使这更容易做到。您甚至可以编写 C# 帮助器 class 并从 python 调用它。然后,您可以在自动化界面中打开它,并根据需要将其保存为 XML 格式。