【问题标题】:How to copy multiple XML nodes to another file in Python如何在 Python 中将多个 XML 节点复制到另一个文件
【发布时间】:2014-02-06 00:31:53
【问题描述】:

请记住,我对 Python 很陌生。如果 sample2.xml 中不存在,我正在尝试将几个 XML 节点从 sample1.xml 复制到 out.xml。

这是我卡住之前的距离

import xml.etree.ElementTree as ET

tree = ET.ElementTree(file='sample1.xml')
addtree = ET.ElementTree(file='sample2.xml')

root = tree.getroot()
addroot = addtree.getroot()

for adel in addroot.findall('.//cars/car'):
    for el in root.findall('cars/car'):
        with open('out.xml', 'w+') as f:
            f.write("BEFORE\n")    
            f.write(el.tag)
            f.write("\n")
            f.write(adel.tag)
            f.write("\n")
            f.write("\n")

            f.write("AFTER\n")

            el = adel

            f.write(el.tag)
            f.write("\n")
            f.write(adel.tag)

我不知道我错过了什么,但它只是复制了实际的“tag”本身。

输出如下:

BEFORE
car
car

AFTER
car
car

所以我缺少子节点,还有<></> 标签。预期结果如下。

sample1.xml:

<cars>
    <car>
        <use-car>0</use-car>
        <use-gas>0</use-gas>
        <car-name />
        <car-key />
        <car-location>hawaii</car-location>
        <car-port>5</car-port>
    </car>
</cars>

sample2.xml:

<cars>
    <old>
        1
    </old>
    <new>
        8
    </new>
    <car />
</cars>

out.xml 中的预期结果(最终产品)

<cars>
    <old>
        1
    </old>
    <new>
        8
    </old>
    <car>
        <use-car>0</use-car>
        <use-gas>0</use-gas>
        <car-name />
        <car-key />
        <car-location>hawaii</car-location>
        <car-port>5</car-port>
    </car>
</cars>

所有其他节点 oldnew 必须保持不变。我只是想用它的所有子节点和孙子节点(如果存在)替换 &lt;car /&gt;

【问题讨论】:

    标签: python xml xpath elementtree


    【解决方案1】:

    首先,您的 XML 有几个小问题:

    • sample1:结束 cars 标记缺少 /
    • sample2:结束new 标签错误地读取old,应该读取new

    第二,免责声明:我下面的解决方案有其局限性 - 特别是,它不会处理重复将 sample1 中的 car 节点替换为多个点样本2。但它适用于您提供的示例文件。

    第三:感谢access ElementTree node parent node 上的前几个答案 - 他们告知了下面get_node_parent_info 的实施。

    最后,代码:

    import xml.etree.ElementTree as ET
    
    def find_child(node, with_name):
        """Recursively find node with given name"""
        for element in list(node):
            if element.tag == with_name:
                return element
            elif list(element):
                sub_result = find_child(element, with_name)
                if sub_result is not None:
                    return sub_result
        return None
    
    def replace_node(from_tree, to_tree, node_name):
        """
        Replace node with given node_name in to_tree with
        the same-named node from the from_tree
        """
        # Find nodes of given name ('car' in the example) in each tree
        from_node = find_child(from_tree.getroot(), node_name)
        to_node = find_child(to_tree.getroot(), node_name)
    
        # Find where to substitute the from_node into the to_tree
        to_parent, to_index = get_node_parent_info(to_tree, to_node)
    
        # Replace to_node with from_node
        to_parent.remove(to_node)
        to_parent.insert(to_index, from_node)
    
    def get_node_parent_info(tree, node):
        """
        Return tuple of (parent, index) where:
            parent = node's parent within tree
            index = index of node under parent
        """
        parent_map = {c:p for p in tree.iter() for c in p}
        parent = parent_map[node]
        return parent, list(parent).index(node)
    
    from_tree = ET.ElementTree(file='sample1.xml')
    to_tree = ET.ElementTree(file='sample2.xml')
    
    replace_node(from_tree, to_tree, 'car')
    
    # ET.dump(to_tree)
    to_tree.write('output.xml')
    

    更新:最近引起我注意的是,如果有问题的“孩子”不在 XML 的第一个分支中,那么在我最初提供的解决方案中实现 find_child() 将失败被遍历的树。我已经更新了上面的实现来纠正这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      • 2010-10-31
      • 1970-01-01
      • 1970-01-01
      • 2017-05-15
      • 1970-01-01
      • 2012-08-16
      相关资源
      最近更新 更多