You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python字典转XML脚本生成重复FirstChild元素,求修正方案

问题:字典转XML工具重复生成FirstChild元素的修正

我正在开发一款通过config_table定义节点关系的通用字典转XML工具,当前Python脚本输出接近预期,但每个数据项都会生成独立的FirstChild元素,导致该元素重复。以下是脚本、实际输出和预期输出,求修正:

import xml.etree.ElementTree as ET

# Define the config_table and input_data
config_table = [
    {'NODE_ID': 0, 'NODE_NAME': 'RootElement', 'NODE_TYPE': 'element', 'PARENT_ID': None, 'VALUE_FIELD': None, 'KEY_FIELD': 'KEY_ZERO'},
    {'NODE_ID': 1, 'NODE_NAME': 'FirstChild', 'NODE_TYPE': 'element', 'PARENT_ID': 0, 'VALUE_FIELD': None, 'KEY_FIELD': 'KEY_ONE'},
    {'NODE_ID': 2, 'NODE_NAME': 'SecondChild', 'NODE_TYPE': 'element', 'PARENT_ID': 1, 'VALUE_FIELD': None, 'KEY_FIELD': 'KEY_TWO'},
    {'NODE_ID': 3, 'NODE_NAME': 'SecAtt', 'NODE_TYPE': 'attribute', 'PARENT_ID': 2, 'VALUE_FIELD': 'VALUE_THREE', 'KEY_FIELD': 'VALUE_THREE'},
    {'NODE_ID': 4, 'NODE_NAME': 'ThirdChild', 'NODE_TYPE': 'text', 'PARENT_ID': 2, 'VALUE_FIELD': '', 'KEY_FIELD': 'VALUE_FOUR'},
]

input_data = [
    {'KEY_ZERO': 1, 'KEY_ONE': 1, 'KEY_TWO': 1, 'VALUE_THREE': 'alpha', 'VALUE_FOUR': 'The first letter of the Greek alphabet'},
    {'KEY_ZERO': 1, 'KEY_ONE': 1, 'KEY_TWO': 2, 'VALUE_THREE': 'beta', 'VALUE_FOUR': 'The second letter of the Greek alphabet'},
    {'KEY_ZERO': 1, 'KEY_ONE': 1, 'KEY_TWO': 3, 'VALUE_THREE': 'gamma', 'VALUE_FOUR': 'The third letter of the Greek alphabet'},
    {'KEY_ZERO': 1, 'KEY_ONE': 2, 'KEY_TWO': 4, 'VALUE_THREE': 'ay', 'VALUE_FOUR': 'The first letter of the English alphabet'},
    {'KEY_ZERO': 1, 'KEY_ONE': 3, 'KEY_TWO': 5, 'VALUE_THREE': 'alif', 'VALUE_FOUR': 'The first letter of the Arabic alphabet'}
]

# Function to create XML from the config_table and input_data
def create_xml(config_table, input_data):
    # Helper function to find node by ID
    def find_node_by_id(node_id):
        for node in config_table:
            if node['NODE_ID'] == node_id:
                return node
        return None

    # Helper function to build XML recursively
    def build_xml(parent, parent_node_id, data):
        for node in config_table:
            if node['PARENT_ID'] == parent_node_id:
               
                if node['NODE_TYPE'] == 'element':
                    element = ET.SubElement(parent, node['NODE_NAME'])
                   
                    # Add KEY_FIELD attributes
                    #if node['KEY_FIELD'] in data:
                        #element.set(node['KEY_FIELD'], str(data[node['KEY_FIELD']]))
                   
                    build_xml(element, node['NODE_ID'], data)
                elif node['NODE_TYPE'] == 'attribute':
                    parent.set(node['NODE_NAME'], data[node['VALUE_FIELD']])
                elif node['NODE_TYPE'] == 'text':
                    element = ET.SubElement(parent,node['NODE_NAME'])
                    element.text = data[node['KEY_FIELD']]
                   
                # Add KEY_FIELD attributes at each level
                #if node['KEY_FIELD'] in data:
                    #parent.set(node['KEY_FIELD'], str(data[node['KEY_FIELD']]))

    # Create the root element
    root_node = find_node_by_id(0)
    root = ET.Element(root_node['NODE_NAME'])

    # Build the XML tree for each item in the input data
    for data in input_data:
        build_xml(root, 0, data)

    # Convert the tree to a string
    xml_str = ET.tostring(root, encoding='unicode', method='xml')
    return xml_str

# Generate the XML
xml_output = create_xml(config_table, input_data)
print(xml_output)

实际输出

<RootElement>
    <FirstChild>
        <SecondChild SecAtt="alpha">
            <ThirdChild>The first letter of the Greek alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
    <FirstChild>
        <SecondChild SecAtt="beta">
            <ThirdChild>The second letter of the Greek alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
    <FirstChild>
        <SecondChild SecAtt="gamma">
            <ThirdChild>The third letter of the Greek alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
    <FirstChild>
        <SecondChild SecAtt="ay">
            <ThirdChild>The first letter of the English alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
    <FirstChild>
        <SecondChild SecAtt="alif">
            <ThirdChild>The first letter of the Arabic alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
</RootElement>

预期输出

<RootElement>
    <FirstChild>
        <SecondChild SecAtt="alpha">
            <ThirdChild>The first letter of the Greek alphabet</ThirdChild>
        </SecondChild>
        <SecondChild SecAtt="beta">
            <ThirdChild>The second letter of the Greek alphabet</ThirdChild>
        </SecondChild>
        <SecondChild SecAtt="gamma">
            <ThirdChild>The third letter of the Greek alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
    <FirstChild>
        <SecondChild SecAtt="ay">
            <ThirdChild>The first letter of the English alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
    <FirstChild>
        <SecondChild SecAtt="alif">
            <ThirdChild>The first letter of the Arabic alphabet</ThirdChild>
        </SecondChild>
    </FirstChild>
</RootElement>

解决方案

核心问题是当前脚本为每条数据从头构建完整节点树,导致相同KEY_ONE值的FirstChild被重复创建。需要先按FirstChild对应的KEY_FIELD(即KEY_ONE)对输入数据分组,再针对每组数据构建节点:同一组的所有数据共享一个FirstChild节点,将对应的SecondChild挂到该节点下。

修改后的create_xml函数如下:

def create_xml(config_table, input_data):
    # Helper function to find node by ID
    def find_node_by_id(node_id):
        for node in config_table:
            if node['NODE_ID'] == node_id:
                return node
        return None

    # Helper function to build XML starting from a specific node ID
    def build_xml_from_node(parent, start_node_id, data):
        for node in config_table:
            if node['NODE_ID'] == start_node_id:
                if node['NODE_TYPE'] == 'element':
                    element = ET.SubElement(parent, node['NODE_NAME'])
                    # Recursively build child nodes
                    build_child_nodes(element, node['NODE_ID'], data)
                elif node['NODE_TYPE'] == 'attribute':
                    parent.set(node['NODE_NAME'], data[node['VALUE_FIELD']])
                elif node['NODE_TYPE'] == 'text':
                    element = ET.SubElement(parent, node['NODE_NAME'])
                    element.text = data[node['KEY_FIELD']]

    # Helper function to build child nodes recursively
    def build_child_nodes(parent_element, parent_node_id, data):
        for node in config_table:
            if node['PARENT_ID'] == parent_node_id:
                if node['NODE_TYPE'] == 'element':
                    element = ET.SubElement(parent_element, node['NODE_NAME'])
                    build_child_nodes(element, node['NODE_ID'], data)
                elif node['NODE_TYPE'] == 'attribute':
                    parent_element.set(node['NODE_NAME'], data[node['VALUE_FIELD']])
                elif node['NODE_TYPE'] == 'text':
                    element = ET.SubElement(parent_element, node['NODE_NAME'])
                    element.text = data[node['KEY_FIELD']]

    # Create the root element
    root_node = find_node_by_id(0)
    root = ET.Element(root_node['NODE_NAME'])

    # Get FirstChild's KEY_FIELD to group data
    first_child_node = find_node_by_id(1)
    group_key = first_child_node['KEY_FIELD']

    # Group input_data by the group_key (KEY_ONE)
    from collections import defaultdict
    grouped_data = defaultdict(list)
    for data in input_data:
        grouped_data[data[group_key]].append(data)

    # Build XML for each group
    for data_list in grouped_data.values():
        # Create FirstChild element under root
        first_child = ET.SubElement(root, first_child_node['NODE_NAME'])
        # For each data in the group, build from SecondChild (NODE_ID=2)
        for data in data_list:
            build_xml_from_node(first_child, 2, data)

    # Convert the tree to a string
    xml_str = ET.tostring(root, encoding='unicode', method='xml')
    return xml_str

运行修改后的代码即可得到预期的XML输出。

内容的提问来源于stack exchange,提问作者user1386812

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:17:03