Python:非侵入式地处理XML文件



我有大量的XML文件,我想在其中进行以下更改:

  1. 根元素下创建一个新元素 - 我们称之为new_element

  2. 找到另一个嵌套更深的特定元素 - 我们称之为existing_element- 并移动它,使其成为new_element的子元素

我想以尽可能少的侵入性方式执行此操作,以便旧文件和新文件之间的差异仅显示属于新创建的元素(因此已添加到文件中(或曾经属于已移动的元素(因此已从文件中删除(的行的更改。我想使用 Python 3 来做到这一点。

但是,当我尝试只读取其中一个 XML 文件时xml.dom.minidom并将我刚刚读取的内容写入新文件并区分这两个文件时,每一行都被标记为已更改(可能是因为它们包含不同类型的换行符(。此外,当我查看这两个文件的内容时,我看到 XML 声明中的编码规范以及声明后的换行符已经消失,并且整个文档中标签中的属性在标签中的顺序都被打乱了。

使用xml.etree.ElementTree时的情况非常相似,只是现在整个XML声明消失了,所有标签名称前面都带有"ns0:"(出于某种原因(,并且某些属性名称后面跟着":ns0"。

对XML文件的这些"额外"修改都不是可取的,因为我希望能够区分旧文件和新文件,并能够轻松查看已更改的内容和未更改的内容。

那么,有没有一些简单的方法来基于另一个XML文件创建一个新的XML文件,该文件只引入对真正应该更改的行的更改,而保留所有其他行不变,并且不涉及编写自己的代码来解析XML数据?

编辑:这是我想要处理的文件的结构(因为我不知道什么会导致任何建议的代码工作或不能处理我的XML文件,我只删除了存储在文件中三个不同位置的数据 - 我用"*data*"替换了它们 - 并保留其他所有内容(:

<?xml version="1.0" encoding="UTF-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor/>
<created>2017-01-23T12:01:30Z</created>
<modified>2017-01-23T12:01:30Z</modified>
<unit/>
<up_axis>Z_UP</up_axis>
</asset>
<library_visual_scenes>
<visual_scene id="defaultScene">
<node id="sceneRoot">
<instance_geometry url="#geometry">
<bind_material>
<technique_common>
<instance_material symbol="geometry_material" target="#material">
<bind_vertex_input semantic="texcoord0" input_semantic="TEXCOORD" input_set="0"/>
</instance_material>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<library_geometries>
<geometry id="geometry">
<mesh>
<source id="geometry-positions">
<float_array id="geometry-positions-array" count="673731">*data*</float_array>
<technique_common>
<accessor count="224577" source="#geometry-positions-array" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geometry-texcoord_0">
<float_array id="geometry-texcoord_0-array" count="449154">*data*</float_array>
<technique_common>
<accessor count="224577" source="#geometry-texcoord_0-array" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="geometry-vertices">
<input semantic="POSITION" source="#geometry-positions"/>
</vertices>
<triangles count="329753" material="geometry_material">
<input offset="0" semantic="VERTEX" source="#geometry-vertices" set="0"/>
<input offset="1" semantic="TEXCOORD" source="#geometry-texcoord_0" set="0"/>
<p>*data*</p>
</triangles>
</mesh>
</geometry>
</library_geometries>
<library_materials>
<material id="material">
<instance_effect url="#material_effect"/>
</material>
</library_materials>
<library_effects>
<effect id="material_effect">
<profile_COMMON>
<image id="material_effect-image" height="0" width="0">
<init_from>Tile_+037_+047_0.jpg</init_from>
</image>
<newparam sid="material_effect-surface">
<surface type="2D">
<init_from>material_effect-image</init_from>
</surface>
</newparam>
<newparam sid="material_effect-sampler">
<sampler2D>
<source>material_effect-surface</source>
<wrap_s>CLAMP</wrap_s>
<wrap_t>CLAMP</wrap_t>
<minfilter>LINEAR_MIPMAP_LINEAR</minfilter>
<magfilter>LINEAR</magfilter>
<border_color>0 0 0 0</border_color>
</sampler2D>
</newparam>
<technique sid="t0">
<phong>
<emission>
<color>0 0 0 1</color>
</emission>
<ambient>
<color>1 1 1 1</color>
</ambient>
<diffuse>
<texture texture="material_effect-sampler" texcoord="texcoord0">
<extra type="color">
<technique profile="SCEI">
<color>1 1 1 1</color>
</technique>
</extra>
</texture>
</diffuse>
<specular>
<color>0 0 0 1</color>
</specular>
<shininess>
<float>0</float>
</shininess>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<scene>
<instance_visual_scene url="#defaultScene"/>
</scene>
</COLLADA>

这就是我希望 XML 变成的内容:

<?xml version="1.0" encoding="UTF-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor/>
<created>2017-01-23T12:01:30Z</created>
<modified>2017-01-23T12:01:30Z</modified>
<unit/>
<up_axis>Z_UP</up_axis>
</asset>
<library_visual_scenes>
<visual_scene id="defaultScene">
<node id="sceneRoot">
<instance_geometry url="#geometry">
<bind_material>
<technique_common>
<instance_material symbol="geometry_material" target="#material">
<bind_vertex_input semantic="texcoord0" input_semantic="TEXCOORD" input_set="0"/>
</instance_material>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<library_geometries>
<geometry id="geometry">
<mesh>
<source id="geometry-positions">
<float_array id="geometry-positions-array" count="673731">*data*</float_array>
<technique_common>
<accessor count="224577" source="#geometry-positions-array" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geometry-texcoord_0">
<float_array id="geometry-texcoord_0-array" count="449154">*data*</float_array>
<technique_common>
<accessor count="224577" source="#geometry-texcoord_0-array" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="geometry-vertices">
<input semantic="POSITION" source="#geometry-positions"/>
</vertices>
<triangles count="329753" material="geometry_material">
<input offset="0" semantic="VERTEX" source="#geometry-vertices" set="0"/>
<input offset="1" semantic="TEXCOORD" source="#geometry-texcoord_0" set="0"/>
<p>*data*</p>
</triangles>
</mesh>
</geometry>
</library_geometries>
<library_materials>
<material id="material">
<instance_effect url="#material_effect"/>
</material>
</library_materials>
<library_effects>
<effect id="material_effect">
<profile_COMMON>
<newparam sid="material_effect-surface">
<surface type="2D">
<init_from>material_effect-image</init_from>
</surface>
</newparam>
<newparam sid="material_effect-sampler">
<sampler2D>
<source>material_effect-surface</source>
<wrap_s>CLAMP</wrap_s>
<wrap_t>CLAMP</wrap_t>
<minfilter>LINEAR_MIPMAP_LINEAR</minfilter>
<magfilter>LINEAR</magfilter>
<border_color>0 0 0 0</border_color>
</sampler2D>
</newparam>
<technique sid="t0">
<phong>
<emission>
<color>0 0 0 1</color>
</emission>
<ambient>
<color>1 1 1 1</color>
</ambient>
<diffuse>
<texture texture="material_effect-sampler" texcoord="texcoord0">
<extra type="color">
<technique profile="SCEI">
<color>1 1 1 1</color>
</technique>
</extra>
</texture>
</diffuse>
<specular>
<color>0 0 0 1</color>
</specular>
<shininess>
<float>0</float>
</shininess>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<scene>
<instance_visual_scene url="#defaultScene"/>
</scene>
<library_images>
<image id="material_effect-image" height="0" width="0">
<init_from>Tile_+037_+047_0.jpg</init_from>
</image>
</library_images>
</COLLADA>

请注意,在 XML 的第二部分中,如何在根元素下创建名为library_images的标记(根元素下并不重要,只要它是它的直接子元素(,并且元素image已移动到其中。

是的,有一种称为XSLT的方法,这是一种特殊用途的语言,旨在将XML文件从一种结构转换为另一种结构或其他格式,包括HTML,TXT/CSV,甚至JSON。Python 的第三方模块,lxml可以运行 XSLT 1.0 脚本(不是内置的minidometree模块(。但是,其他语言(Java,C#,PHP,VB(和软件(Saxon,Xalan,libxslt,.NET(也可以运行此类脚本,甚至是2.0和3.0脚本。Python 可以通过命令行调用连接到这些外部解决方案。

具体而言,运行标识转换以按原样保留原始格式,然后将所需的更改应用于特定节点。一个挑战是在创建新元素库图像时需要定义前缀、文档namespace的默认命名空间的处理:

XSLT(另存为 .xsl(

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:doc="http://www.collada.org/2005/11/COLLADASchema">
<xsl:output omit-xml-declaration="no" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- IDENTITY TRANSFORM -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- ADD <new_element> AS CHILD TOO ROOT  -->
<xsl:template match="/*">
<xsl:copy>          
<xsl:apply-templates select="@*|node()"/>
<xsl:element name="library-images" namespace="http://www.collada.org/2005/11/COLLADASchema">
<xsl:copy-of select="descendant::doc:profile_COMMON/doc:image"/>
</xsl:element>
</xsl:copy>
</xsl:template>
<!-- REMOVE NODE IN DOCUMENT -->
<xsl:template match="doc:profile_COMMON/doc:image"/>
</xsl:stylesheet>

import lxml.etree as et
# LOAD XML AND XSL
doc = et.parse('my_file.xml')
xsl = et.parse('my_script.xsl')
# CONFIGURE TRANSFORMER
transform = et.XSLT(xsl)    
# RUN TRANSFORMATION WITH PARAMS
result = transform(doc)
# PRINT RESULT
print(result)  
# SAVE TO FILE
with open('output.xml', 'wb') as f:
f.write(result)

输出

XSLT 小提琴演示

<?xml version="1.0" encoding="UTF-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor/>
<created>2017-01-23T12:01:30Z</created>
<modified>2017-01-23T12:01:30Z</modified>
<unit/>
<up_axis>Z_UP</up_axis>
</asset>
<library_visual_scenes>
<visual_scene id="defaultScene">
<node id="sceneRoot">
<instance_geometry url="#geometry">
<bind_material>
<technique_common>
<instance_material symbol="geometry_material" target="#material">
<bind_vertex_input semantic="texcoord0" input_semantic="TEXCOORD" input_set="0"/>
</instance_material>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<library_geometries>
<geometry id="geometry">
<mesh>
<source id="geometry-positions">
<float_array id="geometry-positions-array" count="673731">*data*</float_array>
<technique_common>
<accessor count="224577" source="#geometry-positions-array" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="geometry-texcoord_0">
<float_array id="geometry-texcoord_0-array" count="449154">*data*</float_array>
<technique_common>
<accessor count="224577" source="#geometry-texcoord_0-array" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="geometry-vertices">
<input semantic="POSITION" source="#geometry-positions"/>
</vertices>
<triangles count="329753" material="geometry_material">
<input offset="0" semantic="VERTEX" source="#geometry-vertices" set="0"/>
<input offset="1" semantic="TEXCOORD" source="#geometry-texcoord_0" set="0"/>
<p>*data*</p>
</triangles>
</mesh>
</geometry>
</library_geometries>
<library_materials>
<material id="material">
<instance_effect url="#material_effect"/>
</material>
</library_materials>
<library_effects>
<effect id="material_effect">
<profile_COMMON>
<newparam sid="material_effect-surface">
<surface type="2D">
<init_from>material_effect-image</init_from>
</surface>
</newparam>
<newparam sid="material_effect-sampler">
<sampler2D>
<source>material_effect-surface</source>
<wrap_s>CLAMP</wrap_s>
<wrap_t>CLAMP</wrap_t>
<minfilter>LINEAR_MIPMAP_LINEAR</minfilter>
<magfilter>LINEAR</magfilter>
<border_color>0 0 0 0</border_color>
</sampler2D>
</newparam>
<technique sid="t0">
<phong>
<emission>
<color>0 0 0 1</color>
</emission>
<ambient>
<color>1 1 1 1</color>
</ambient>
<diffuse>
<texture texture="material_effect-sampler" texcoord="texcoord0">
<extra type="color">
<technique profile="SCEI">
<color>1 1 1 1</color>
</technique>
</extra>
</texture>
</diffuse>
<specular>
<color>0 0 0 1</color>
</specular>
<shininess>
<float>0</float>
</shininess>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<scene>
<instance_visual_scene url="#defaultScene"/>
</scene>
<library-images>
<image id="material_effect-image" height="0" width="0">
<init_from>Tile_+037_+047_0.jpg</init_from>
</image>
</library-images>
</COLLADA>

相关内容

  • 没有找到相关文章

最新更新