Python:以非介入方式使用XML文件

时间:2018-06-21 15:48:44

标签: python xml xml-parsing elementtree minidom

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

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

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

  3. 的子元素

我想以最小的介入方式做到这一点,以使旧文件和新文件之间的差异仅显示属于新创建元素(因此已添加到文件)的行上的更改。或曾经属于被移动的元素(因此已从文件中删除)。我想使用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已移入其中。

1 个答案:

答案 0 :(得分:2)

是的,有一种叫做XSLT的方式,一种特殊目的的语言旨在将XML文件从一种结构转换为另一种或其他格式,包括HTML,TXT / CSV,甚至JSON。 Python的第三方模块lxml可以运行XSLT 1.0脚本(不是内置的minidometree模块)。但是,其他语言(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)

输出

XSLT Fiddle Demo

<?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>