如何删除 XML 文件中的重复元素
How to delete duplicated elements in XML file
这是我的 XML 文件:它包含一个重复的元素 <houseNum>0</houseNum>
。
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfHouse>
<XmlForm>
<houseNum>0</houseNum>
<plan1>
<coord>
<X> 1.2 </X>
<Y> 2.1 </Y>
<Z> 3.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan1>
<plan2>
<coord>
<X> 21.2 </X>
<Y> 22.1 </Y>
<Z> 31.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan2>
</XmlForm>
<XmlForm>
<houseNum>0</houseNum>
<plan1>
<coord>
<X> 1.2 </X>
<Y> 2.1 </Y>
<Z> 3.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan1>
<plan2>
<coord>
<X> 21.2 </X>
<Y> 22.1 </Y>
<Z> 31.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan2>
</XmlForm>
<XmlForm>
<houseNum>1</houseNum>
<plan1>
<coord>
<X> 11.2 </X>
<Y> 12.1 </Y>
<Z> 13.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 255 </G>
<B> 0 </B>
</color>
</plan1>
<plan2>
<coord>
<X> 211.2 </X>
<Y> 212.1 </Y>
<Z> 311.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 255 </B>
</color>
</plan2>
</XmlForm>
</ArrayOfHouse>
在我的例子中,有两种类型的重复:
1) 如果重复的元素是连续的,这里是我删除重复元素的代码,我只是比较element[i]和element[i+1],如果这些elemet[i .text==element[i+1].text,我删除element[i+1]
from lxml import etree
def Remove_Duplication_XML(xml_file):
base_name = os.path.basename(xml_file)
start_time = time.time()
tree = etree.parse(xml_file)
# remove duplicate skeletons
root = tree.getroot()
elementlist = [e for e in root.iter('houseNum')]
numframes=[x.text for x in elementlist]
print(numframes)
for index_element in range(1, len(elementlist)):
try:
if elementlist[index_element].text == elementlist[index_element - 1].text:
elementlist[index_element].getparent().remove(elementlist[index_element])
print(elementlist[index_element].text)
except:
print(' except ')
# String xml without duplication
file = etree.tostring(root).decode("utf-8")
print(file)
2) 如果重复的元素不连续,我正在找一行工作来做。有帮助吗?
考虑一下 XSLT,一种专门用于转换 XML 文件的语言(类似于使用 SQL,也是一种特殊用途,用于查询数据库)。并且因为您已经使用了 Python 的 lxml
,您可以无缝地 运行 这样的脚本,而无需单个 for
循环或 if
逻辑来删除重复项 文档中的任意位置。
具体来说,运行 Muenchian Grouping,一种 XSLT 1.0 方法,使用 [=16] 通过 houseNum 索引您的 XML 文档=] 然后 return 个不同的分组。还有一个额外的好处,下面的 XSLT 甚至删除了带有漂亮打印缩进的文本节点中的白色 spaces:
XSLT (另存为.xsl文件,一个特殊的.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:key name="id" match="XmlForm" use="houseNum" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="XmlForm[generate-id() != generate-id(key('id', houseNum))]"/>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
Python
import os
import lxml.etree as et
# LOAD XML AND XSL FILES
xml = et.parse('Source.xml')
xsl = et.parse('XSLTScript.xsl')
# TRANSFORM SOURCE
transform = et.XSLT(xsl)
result = transform(xml)
# PRINT RESULT TO SCREEN
print(result)
# SAVE RESULT TO FILE
with open('Output.xml', 'wb') as f:
f.write(result)
输出 (通知文本值被删除为空 space)
<?xml version="1.0"?>
<ArrayOfHouse>
<XmlForm>
<houseNum>0</houseNum>
<plan1>
<coord>
<X>1.2</X>
<Y>2.1</Y>
<Z>3.0</Z>
</coord>
<color>
<R>255</R>
<G>0</G>
<B>0</B>
</color>
</plan1>
<plan2>
<coord>
<X>21.2</X>
<Y>22.1</Y>
<Z>31.0</Z>
</coord>
<color>
<R>255</R>
<G>0</G>
<B>0</B>
</color>
</plan2>
</XmlForm>
<XmlForm>
<houseNum>1</houseNum>
<plan1>
<coord>
<X>11.2</X>
<Y>12.1</Y>
<Z>13.0</Z>
</coord>
<color>
<R>255</R>
<G>255</G>
<B>0</B>
</color>
</plan1>
<plan2>
<coord>
<X>211.2</X>
<Y>212.1</Y>
<Z>311.0</Z>
</coord>
<color>
<R>255</R>
<G>0</G>
<B>255</B>
</color>
</plan2>
</XmlForm>
</ArrayOfHouse>
这是我的 XML 文件:它包含一个重复的元素 <houseNum>0</houseNum>
。
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfHouse>
<XmlForm>
<houseNum>0</houseNum>
<plan1>
<coord>
<X> 1.2 </X>
<Y> 2.1 </Y>
<Z> 3.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan1>
<plan2>
<coord>
<X> 21.2 </X>
<Y> 22.1 </Y>
<Z> 31.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan2>
</XmlForm>
<XmlForm>
<houseNum>0</houseNum>
<plan1>
<coord>
<X> 1.2 </X>
<Y> 2.1 </Y>
<Z> 3.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan1>
<plan2>
<coord>
<X> 21.2 </X>
<Y> 22.1 </Y>
<Z> 31.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 0 </B>
</color>
</plan2>
</XmlForm>
<XmlForm>
<houseNum>1</houseNum>
<plan1>
<coord>
<X> 11.2 </X>
<Y> 12.1 </Y>
<Z> 13.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 255 </G>
<B> 0 </B>
</color>
</plan1>
<plan2>
<coord>
<X> 211.2 </X>
<Y> 212.1 </Y>
<Z> 311.0 </Z>
</coord>
<color>
<R> 255 </R>
<G> 0 </G>
<B> 255 </B>
</color>
</plan2>
</XmlForm>
</ArrayOfHouse>
在我的例子中,有两种类型的重复:
1) 如果重复的元素是连续的,这里是我删除重复元素的代码,我只是比较element[i]和element[i+1],如果这些elemet[i .text==element[i+1].text,我删除element[i+1]
from lxml import etree
def Remove_Duplication_XML(xml_file):
base_name = os.path.basename(xml_file)
start_time = time.time()
tree = etree.parse(xml_file)
# remove duplicate skeletons
root = tree.getroot()
elementlist = [e for e in root.iter('houseNum')]
numframes=[x.text for x in elementlist]
print(numframes)
for index_element in range(1, len(elementlist)):
try:
if elementlist[index_element].text == elementlist[index_element - 1].text:
elementlist[index_element].getparent().remove(elementlist[index_element])
print(elementlist[index_element].text)
except:
print(' except ')
# String xml without duplication
file = etree.tostring(root).decode("utf-8")
print(file)
2) 如果重复的元素不连续,我正在找一行工作来做。有帮助吗?
考虑一下 XSLT,一种专门用于转换 XML 文件的语言(类似于使用 SQL,也是一种特殊用途,用于查询数据库)。并且因为您已经使用了 Python 的 lxml
,您可以无缝地 运行 这样的脚本,而无需单个 for
循环或 if
逻辑来删除重复项 文档中的任意位置。
具体来说,运行 Muenchian Grouping,一种 XSLT 1.0 方法,使用 [=16] 通过 houseNum 索引您的 XML 文档=] 然后 return 个不同的分组。还有一个额外的好处,下面的 XSLT 甚至删除了带有漂亮打印缩进的文本节点中的白色 spaces:
XSLT (另存为.xsl文件,一个特殊的.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:key name="id" match="XmlForm" use="houseNum" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="XmlForm[generate-id() != generate-id(key('id', houseNum))]"/>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
Python
import os
import lxml.etree as et
# LOAD XML AND XSL FILES
xml = et.parse('Source.xml')
xsl = et.parse('XSLTScript.xsl')
# TRANSFORM SOURCE
transform = et.XSLT(xsl)
result = transform(xml)
# PRINT RESULT TO SCREEN
print(result)
# SAVE RESULT TO FILE
with open('Output.xml', 'wb') as f:
f.write(result)
输出 (通知文本值被删除为空 space)
<?xml version="1.0"?>
<ArrayOfHouse>
<XmlForm>
<houseNum>0</houseNum>
<plan1>
<coord>
<X>1.2</X>
<Y>2.1</Y>
<Z>3.0</Z>
</coord>
<color>
<R>255</R>
<G>0</G>
<B>0</B>
</color>
</plan1>
<plan2>
<coord>
<X>21.2</X>
<Y>22.1</Y>
<Z>31.0</Z>
</coord>
<color>
<R>255</R>
<G>0</G>
<B>0</B>
</color>
</plan2>
</XmlForm>
<XmlForm>
<houseNum>1</houseNum>
<plan1>
<coord>
<X>11.2</X>
<Y>12.1</Y>
<Z>13.0</Z>
</coord>
<color>
<R>255</R>
<G>255</G>
<B>0</B>
</color>
</plan1>
<plan2>
<coord>
<X>211.2</X>
<Y>212.1</Y>
<Z>311.0</Z>
</coord>
<color>
<R>255</R>
<G>0</G>
<B>255</B>
</color>
</plan2>
</XmlForm>
</ArrayOfHouse>