1. 假设需要对以下 3 个文件进行合并

  • file1.xml
<!-- file1.xml -->
<data>
<item id="1" value="a">Item 1</item>
<item id="2" value="b">Item 2</item>
<item id="1" value="c">Item 3</item>
<item id="1" value="a">Item 4</item>
</data>
  • file2.xml
<!-- file2.xml -->
<data>
<item id="1" value="a">Item A</item>
<item id="1" value="b">Item B</item>
<item id="3" value="c">Item C</item>
<item id="1" value="a">Item D</item>
</data>
  • file3.xml
<!-- file3.xml -->
<data>
<item id="1" value="a">
<subitem>Subitem X</subitem>
</item>
<item id="4" value="d">Item P</item>
<item id="1" value="a">
<subitem>Subitem Y</subitem>
</item>
</data>

2. 合并输出的预计结果保存在 output.xml 中

  • 合并条件是满足 {'id': '1','value':'a'} 的所有元素
<!-- output.xml -->
<data>
<item id="1" value="a">Item 1</item>
<item id="1" value="a">Item 4</item>
<item id="1" value="a">Item A</item>
<item id="1" value="a">Item D</item>
<item id="1" value="a">
<subitem>Subitem X</subitem>
</item>
<item id="1" value="a">
<subitem>Subitem Y</subitem>
</item>
</data>

3. 合并方式一(根节点简单的情况)

  • 合并的方法如merge_xml_files_root所示
def merge_xml_files_root(xml_files,root_data,item,attribs, output_file):
root = ET.Element(root_data)
for xml_file in xml_files:
subtree = ET.parse(xml_file)
subroot = subtree.getroot()
attrib = [f"[@{k}='{v}']" for k,v in attribs.items()]
for elem in subroot.findall(f"./{item}/{''.join(attrib)}"):
root.append(elem)
tree = ET.ElementTree(root)
tree.write(output_file)
tree.write(output_file)
if __name__ == '__main__':
xml_files = ['file1.xml','file2.xml','file3.xml']
attribs = {'id': '1','value':'a'}
output_file = 'output.xml'
item = 'item'
root_data = 'data'
merge_xml_files_root(xml_files,root_data,item,attribs,output_file)

4. 合并方式二(根节点未知)

  • 合并的方法如merge_xml_files所示
def merge_xml_files(xml_files,item,attribs, output_file):
tree = None
for xml_file in xml_files:
if not tree:
# 使用第一个文件初始化tree
tree = ET.parse(xml_file)
root = tree.getroot()
for elem in root.findall(f"./{item}"):
if any(elem.attrib.get(key)!=value for key, value in attribs.items()):
# 请除第一个文件中不符合的结点
root.remove(elem)
continue
root = tree.getroot()
subtree = ET.parse(xml_file)
subroot = subtree.getroot()
attrib = [f"[@{k}='{v}']" for k,v in attribs.items()]
for elem in subroot.findall(f"./{item}/{''.join(attrib)}"):
root.append(elem)
tree.write(output_file)
  • 可通过以下方式调用
if __name__ == '__main__':
xml_files = ['file1.xml','file2.xml','file3.xml']
attribs = {'id': '1','value':'a'}
output_file = 'output.xml'
item = 'item'
merge_xml_files(xml_files,item,attribs,output_file)

5. 其他使用方式

  • 如果传入的 attribs = {'id': '1'},将会得到满足该条件的结果,如下:
<!-- output.xml -->
<data>
<item id="1" value="a">Item 1</item>
<item id="1" value="c">Item 3</item>
<item id="1" value="a">Item 4</item>
<item id="1" value="a">Item A</item>
<item id="1" value="b">Item B</item>
<item id="1" value="a">Item D</item>
<item id="1" value="a">
<subitem>Subitem X</subitem>
</item>
<item id="1" value="a">
<subitem>Subitem Y</subitem>
</item>
</data>

6. 扩充部分

  • 合并方式二使用any()函数进行结点删除,此外还有all()函数。any()all() 都是 Python 内置函数。any() 函数用于判断给定的可迭代参数iterable 是否全部为 False,则返回 False,如果有一个为 True,则返回 True。元素除了是 0、空、FALSE 外都算 TRUE。

6.1 any()函数

  • any() 函数接受一个可迭代对象作为参数,如果可迭代对象中的任意一个元素为真值,则返回 True,否则返回 False。例如:
print(any([False, False, True])) # 输出 True
print(any([False, False, False])) # 输出 False
  • 文中使用的
if any(elem.attrib.get(key)!=value for key, value in attribs.items()
  • 等价于
if elem.attrib.get('id')!='1' or elem.attrib.get('value')!='a'

6.2 all()函数

  • all()函数也接受一个可迭代对象作为参数,如果可迭代对象中的所有元素都为真值,则返回 True,否则返回 False。例如:
print(all([True, True, True])) # 输出 True
print(all([True, False, True])) # 输出 False