python - 在每个元素后按标签插入 XML 节点

我有以下 xml 并且我想在每个 </subMenu> 之后插入一个 <separatorItem/> ,并且它后面有一个 <scriptItem/>

或者换句话说,您可以改写,因为我想在 xml 层次结构的每个级别插入一个 <separatorItem/> 在同一级别内包含更多元素的最后一个 <subMenu> 之后。

<?xml version="1.0" encoding="UTF-8"?>
<mainMenu>
    <menuBar>
        <subMenu>
            <label>Main</label>
            <subMenu>
                <label>Sub Menu</label>
                <subMenu>
                    <label>Sub-Sub Menu</label>
                    <scriptItem>
                        <label>Email</label>
                    </scriptItem>
                </subMenu>
                <scriptItem>
                    <label>Manager</label>
                </scriptItem>
            </subMenu>
            <subMenu>
                <label>Dev</label>
                <scriptItem>
                    <label>Dialog</label>
                </scriptItem>
            </subMenu>
            <scriptItem>
                <label>Sample</label>
            </scriptItem>
            <scriptItem>
                <label>Home</label>
            </scriptItem>
            <scriptItem>
                <label>Browser</label>
            </scriptItem>
            <scriptItem>
                <label>Check</label>
            </scriptItem>
            <scriptItem>
                <label>Open</label>
            </scriptItem>
            <scriptItem>
                <label>Close</label>
            </scriptItem>
        </subMenu>
    </menuBar>
</mainMenu>

起始码

import os
import re
import sys
import logging
import xml.dom.minidom
import xml.etree.ElementTree as ET


fp = os.path.abspath('elementTree.xml')
tree = ET.parse(fp)
root = tree.getroot()

# insert separator after every subMenu that's followed by a scriptItem
# parent = None
# for el in root.iter():
    # parent = root # find correct subMenu to place sep after
    # sep = ET.SubElement(parent, 'separatorItem')
sep = ET.Element('separatorItem')
root.insert(1, sep)


xmlstr = ET.tostring(root, encoding='UTF-8', method="xml")
xmlObj = xml.dom.minidom.parseString(xmlstr)
xmlstr = xmlObj.toprettyxml(encoding='UTF-8')

menuFilepath = os.path.abspath('updated.xml')
with open(menuFilepath, 'wb') as output:
    output.write(xmlstr)

最终目标看起来像这样......

<?xml version="1.0" encoding="UTF-8"?>
<mainMenu>
    <menuBar>
        <subMenu>
            <label>Main</label>
            <subMenu>
                <label>Sub Menu</label>
                <subMenu>
                    <label>Sub-Sub Menu</label>
                    <scriptItem>
                        <label>Email</label>
                    </scriptItem>
                </subMenu>
                <separatorItem/> <!-- INSERTED !-->
                <scriptItem>
                    <label>Manager</label>
                </scriptItem>
            </subMenu>
            <subMenu>
                <label>Dev</label>
                <scriptItem>
                    <label>Dialog</label>
                </scriptItem>
            </subMenu>
            <separatorItem/> <!-- INSERTED !-->
            <scriptItem>
                <label>Sample</label>
            </scriptItem>
            <scriptItem>
                <label>Home</label>
            </scriptItem>
            <scriptItem>
                <label>Browser</label>
            </scriptItem>
            <scriptItem>
                <label>Check</label>
            </scriptItem>
            <scriptItem>
                <label>Open</label>
            </scriptItem>
            <scriptItem>
                <label>Close</label>
            </scriptItem>
        </subMenu>
    </menuBar>
</mainMenu>

回答1

我会改用 lxml,因为它有更好的 xpath 支持:

from lxml import etree as etree
menus = """[your xml above]"""

doc = etree.fromstring(menus.encode())
targets = doc.xpath('//subMenu[not(.//subMenu)][./scriptItem]')
for target in targets:
    sep = etree.fromstring("""<separatorItem/>""".encode())
    target.addnext(sep)       

print(etree.tostring(doc).decode())

输出应该是您要查找的内容。

相似文章

perl - cpan 模块安装失败,没有缺少先决条件

只是试图安装一个CPAN模块,似乎没有缺少任何先决条件,并且似乎找不到任何指向我需要做些什么来解决这个问题。有人可以理解问题可能是什么吗?除非我绝对确定它可能只是测试的问题,否则我宁愿不强制安装。我查...