Python - 浏览目录中的所有 xml 文件,获取一个元素及其子元素并将它们放置在另一个 xml 文件中的正确位置

Posted

技术标签:

【中文标题】Python - 浏览目录中的所有 xml 文件,获取一个元素及其子元素并将它们放置在另一个 xml 文件中的正确位置【英文标题】:Python - Go through all xml files in directory, take one element with it's sub-elements and place them at correct spot in another xml file 【发布时间】:2021-11-16 18:23:58 【问题描述】:

我在这里遇到一种情况,我必须遍历一个目录中的所有 xml 文件:

Get.xml
Set.xml
Try.xml
etc..

它们每个都有相似的结构但不一样,并且包含这样的元素:

<example atrib1='' atrib2= ''...>
   <summary atrib1='' atrib2= ''...>
      <properties>
      </properties>
   </summary>
   <Elem>
     <element1>
       <element2>
         <subelement2>
             ........ 
         </subelement2>
       <element2>
     <element1>
   </Elem>
</example>

但是我还有其他的,我们称之为 Main.xml,其中包含 Get、Set、Try 作为其元素的名称:

<example atrib1='' atrib2= ''...>
   <summary atrib1='' atrib2= ''...>
      <properties>
      </properties>
   </summary>
   <Test name="Get">
   </Test>
   <Test name="Set">
   </Test>
   <Test name="Try">
   </Test>
</example>

现在我需要如前所述遍历所有 XML 并获取元素及其子元素,并将其放在 Main.xml 中与当前 XML 名称匹配的确切位置,因此 final 应该是:

Main.xml

<example atrib1='' atrib2= ''...>
   <summary atrib1='' atrib2= ''...>
      <properties>
      </properties>
   </summary>
   <Test name="Get">
    <Elem>
       <element1>
         <element2>
           <subelement2>
               ........ 
           </subelement2>
         <element2>
       <element1>
     </Elem>
   </Test>
   <Test name="Set">
     <Elem>
       <element1>
         <element2>
           <subelement2>
               ........ 
           </subelement2>
         <element2>
       <element1>
     </Elem>
   </Test>
   <Test name="Try">
     <Elem>
       <element1>
         <element2>
           <subelement2>
               ........ 
           </subelement2>
         <element2>
       <element1>
     </Elem>
   </Test>
</example>

目前我有这两个函数正在替换不同 xml 文件中的两个相同元素,但很难修复它,因此我可以将整个元素复制到另一个文件的确切位置:

def find_child(node, with_name):
    """Recursively find node with given name"""
    for element in list(node):
        if element.tag == 'Elem':
            return element
        elif list(element):
            sub_result = find_child(element, 'Elem')
            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 in each tree
    from_node = find_child(from_tree.getroot(), 'Elem')
    to_node = find_child(to_tree.getroot(), 'Test')

    # 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)

for filename in files:
    from_tree = ET.ElementTree(filename)
    to_tree = ET.ElementTree(file='Main.xml')
    
    replace_node(from_tree, to_tree, 'Elem')
    
    ET.dump(to_tree)
    to_tree.write('Main.xml')

我知道这行不通,因为我们没有两个相同的元素可以替换,我需要更好的解决方案,请协助!

我也尝试过类似的方法,只是简单地复制整个元素,但没有成功:

source_tree = ET.parse('Get.xml')
source_root = source_tree.getroot() 
dest_tree = ET.parse('Main.xml')
dest_root = dest_tree.getroot()
for element in source_root:
    if element.tag == 'Elem':
        for delement in dest_root.iter('Test'):
            name = delement.get('name')
            if name == 'Get':
                delement.append(element)
                dest_tree.write('Main.xml', encoding='utf-8', xml_declaration=True)

我希望这里必须做什么很清楚.. 如果您对如何做到这一点有任何想法,请告诉我! 谢谢!

【问题讨论】:

【参考方案1】:

我不确定这是否是您想要的,但它会在正确的 Test 元素下插入所有 Elem 元素。

import xml.etree.ElementTree as ET

main_tree = ET.parse('Main.xml')
for test_elem in main_tree.findall('Test'):
    tree = ET.parse(f"test_elem.get('name').xml")
    for elem in tree.findall("Elem"):
        test_elem.append(elem)

with open('newmain.xml', 'wb') as f:
    main_tree.write(f)

【讨论】:

【参考方案2】:

所以我设法写了这个并且它有效,唯一的问题是它没有将 xml 打印为“漂亮的打印”:

files = os.listdir(#location)
for xml in files:
    if xml.endswith('.xml'):
        source_tree = ET.parse(xml)
        source_root = source_tree.getroot() 
        dest_tree = ET.parse('Main.xml')
        dest_root = dest_tree.getroot()
        for element in source_root:
            if element.tag == 'Elem':
                to_copy = element
                for delement in dest_root.iter('Test'):
                        name = delement.get('name')
                        if name+'.xml' == xml:
                            destination_root = delement
                            destination_root.append(to_copy)
                            dest_tree.write('Main.xml', encoding='utf-8', xml_declaration=True)

【讨论】:

在 Python 3.9 中,有一个内置的 indent 函数用于使用 ElementTree 进行漂亮打印:docs.python.org/3/library/…。另请参阅***.com/q/749796/407651。

以上是关于Python - 浏览目录中的所有 xml 文件,获取一个元素及其子元素并将它们放置在另一个 xml 文件中的正确位置的主要内容,如果未能解决你的问题,请参考以下文章

Python自动生成html文件查看指定目录中的所有图片

如何在Python中通过SFTP连接后列出目录中的所有文件夹和文件

如何在Python中通过SFTP连接后列出目录中的所有文件夹和文件

Python zipfile 库 - 从一个目录创建一个仅包含 .pdf 和 .xml 文件的 zip

Bash:无法通过 mediainfo 浏览目录中的所有文件

搜索某个目录下所有jar包中的mapper目录下的xml文件