Python 解析 XML 文件并合并具有相同名称的子节点

162 阅读2分钟

给定一个 XML 文件,该文件包含许多 scen 节点,每个 scen 节点包含一个或多个 case 节点,每个 case 节点又包含一个 res 节点。目标是解析这个 XML 文件,并创建一个新的 XML 文件,其中具有相同名称的 case 节点被合并在一起,而 res 节点的内容被连接成一个字符串。

huake_00152_.jpg

解决方案

  1. 从 XML 文件中提取 scen 节点:
import xml.etree.ElementTree as ET

tree = ET.parse('input.xml')
root = tree.getroot()
scen_nodes = root.findall('.//scen')
  1. 提取 scen 节点中相同名称的 case 节点:
from collections import defaultdict

# 使用字典来存储具有相同名称的 `case` 节点
index = defaultdict(list)
for scen_node in scen_nodes:
    for case_node in scen_node.findall('./case'):
        case_name = case_node.get('name')
        index[case_name].append(case_node)
  1. 创建新的 XML 文件的根节点:
nRoot = ET.Element('root')
  1. 遍历字典中的键值对,并将具有相同名称的 case 节点合并成一个新的 case 节点:
for case_name, case_nodes in index.items():
    # 创建新的 `case` 节点
    new_case_node = ET.Element('case', name=case_name)

    # 将具有相同名称的 `res` 节点的内容连接成一个字符串
    res_list = []
    for case_node in case_nodes:
        res_list.append(case_node.find('./res').text)
    new_case_node.text = ', '.join(res_list)

    # 将新的 `case` 节点添加到 `scen` 节点中
    scen_node = case_nodes[0].getparent()
    scen_node.append(new_case_node)
  1. 将合并后的 scen 节点添加到新的 XML 文件的根节点中:
for scen_node in scen_nodes:
    nRoot.append(scen_node)
  1. 将新的 XML 文件写入文件中:
tree = ET.ElementTree(nRoot)
tree.write('output.xml', encoding='utf-8', xml_declaration=True)

代码例子

# sample input.xml file
input_xml = '''
<root>
    <scen name="n1">
        <case name="c1">
           <res>Text1</res>
        </case>
    </scen>
    <scen name="n2">
        <case name="c234">
           <res>Text</res>
        </case>
    </scen>
    <scen name="n1">
        <case name="c2">
           <res>Text1</res>
        </case>
        <case name="c1">
           <res>Text2</res>
        </case>
    </scen>
</root>
'''

# parse input xml file
input_root = ET.fromstring(input_xml)

# merge case nodes with the same name
def merge_cases(root):
    index = defaultdict(list)
    for scenario in root.findall(".//scenario"):
        index[scenario.get('name')].append(scenario.getchildren())
    nRoot = ET.Element('root')
    elems = []
    for i in index:
        scen = ET.Element('scenario',name=i)
        for elem in index[i]:
            for e in elem:
                scen.append(e)
        elems.append(scen)
    nRoot.extend(elems)
    return nRoot

# create new xml file with merged case nodes
output_root = merge_cases(input_root)

# write output xml file
output_xml = ET.tostring(output_root, encoding='utf-8', xml_declaration=True)
with open('output.xml', 'wb') as f:
    f.write(output_xml)

print('XML file parsed and cases merged successfully!')

运行上面的代码,将在 output.xml 文件中生成新的 XML 文件,其中具有相同名称的 case 节点已经被合并,而 res 节点的内容被连接成一个字符串。