我有大量的XML文件,我想在其中进行以下更改:
在根元素下创建一个新元素–我们称之为new_element
查找嵌套更深的另一个特定元素-我们将其称为existing_element
–并将其移动,使其成为new_element
我想以最小的介入方式做到这一点,以使旧文件和新文件之间的差异仅显示属于新创建元素(因此已添加到文件)的行上的更改。或曾经属于被移动的元素(因此已从文件中删除)。我想使用Python 3做到这一点。
但是,当我尝试仅使用xml.dom.minidom
读取一个XML文件并将我刚刚读取的内容写入一个新文件并比较这两个文件时,每一行都被标记为已更改(可能是因为它们包含不同的行)输入换行符)。此外,当我查看两个文件的内容时,我发现XML声明中的编码规范以及声明后的换行符都消失了,并且整个文档中的标记属性在其中的顺序都被打乱了。标签。
使用xml.etree.ElementTree
时的情况非常相似,只是现在整个XML声明消失了,所有标记名都以“ ns0:
”开头(出于某种原因),并跟随了一些属性名通过“ :ns0
”。
对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
已移入其中。
答案 0 :(得分:2)
是的,有一种叫做XSLT的方式,一种特殊目的的语言旨在将XML文件从一种结构转换为另一种或其他格式,包括HTML,TXT / CSV,甚至JSON。 Python的第三方模块lxml
可以运行XSLT 1.0脚本(不是内置的minidom
或etree
模块)。但是,其他语言(Java,C#,PHP,VB)和软件(Saxon,Xalan,libxslt,.NET)也可以运行此类脚本,甚至2.0 and 3.0 scripts。而且Python可以通过命令行调用连接到这些外部解决方案。
具体来说,运行身份转换以按原样保留原始格式,然后将所需的更改应用于特定节点。一个挑战是如何处理默认名称空间,该名称空间在创建新元素 library-images
时需要定义前缀 doc 和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>
Python
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)
输出
<?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>