首页 > 解决方案 > 如何使用 PYTHON 删除 XML 中的子元素/元素

问题描述

如果 XML 文件中有 2 个或更多条目,则需要一些帮助来删除 old(content[1]...[2]) "ns2:Comment"。每个实例我只需要 1 个“ns2:Comment”。

更新了示例 XML 以便更好地理解:

<?xml version="1.0" encoding="UTF-8"?>
<ns2:Audit >
    <ns2:ProjectInfo>
        <ns2:Name></ns2:Name>
        <ns2:ProjectVersionId></ns2:ProjectVersionId>
        <ns2:WriteDate>2020-01-09</ns2:WriteDate>
    </ns2:ProjectInfo>
    <ns2:IssueList>
        <ns2:Issue instanceId="99999999999999" revision="0">
            <ns2:ManagerAuditTrail></ns2:ManagerAuditTrail>
            <ns2:ClientAuditTrail></ns2:ClientAuditTrail>
            <ns2:ThreadedComments>
                <ns2:Comment>
                    <ns2:Content>test</ns2:Content>
                    <ns2:Username>tester1</ns2:Username>
                    <ns2:Timestamp>2020-01-09</ns2:Timestamp>
                </ns2:Comment>
                <ns2:Comment>
                    <ns2:Content>test</ns2:Content>
                    <ns2:Username>tester2</ns2:Username>
                    <ns2:Timestamp>2020-01-09</ns2:Timestamp>
                </ns2:Comment>
            </ns2:ThreadedComments>
        </ns2:Issue>
        </ns2:Audit>

我创建的脚本:

import xml.etree.ElementTree as ET

tree = ET.parse('audit.xml')
root = tree.getroot()


for x in root[1]:
    for thread in x:
        for content in thread:
            if content[1] is False and content[0] is True:
                pass
            else:
                thread.remove(content)

tree.write('audit1.xml')

标签: pythonxml

解决方案


您示例中的 XML 无效(开始和结束标记的顺序不匹配)。我不知道 ns2: 命名空间来自哪里,但是如果你想在 Etree 中加载它,你必须在根节点中定义那个命名空间。对于这个基于字符串的示例,我取出了 ns2 命名空间。

sample = """<Audit>
<ProjectInfo>
<IssueList>

<Comment>
   <Content>test</Content>
   <Username>tester</Username>
   <Timestamp>2020-01-09</Timestamp>
</Comment>

<Comment>
   <Content>test1</Content>
   <Username>tester2</Username>
   <Timestamp>2020-01-09T</Timestamp>
</Comment>

</IssueList>
</ProjectInfo>
</Audit>"""

如下导入该示例(作为字符串),使用 lxml 因为它更快:

from lxml import etree
tree = etree.fromstring(sample)
root = tree.getroottree()

现在,因为您要查找的评论是嵌套的,所以您也可以使用 Xpath 来获取它们,而不是循环它们。然后,您可以选择它们的父节点并删除索引为 1 或更高的那些的子节点。

commentlist = root.findall('//Comment')

for comment in commentlist[1:]:
   comment.getparent().remove(comment)

etree.tostring(tree)

您必须对命名空间和使用文件进行一些编辑,但这个一般原则是有效的。如果您有很多要保留第一个 Comment 的 IssueList 节点,您可以使用 Xpath 选择所有这些节点,然后遍历子节点,丢弃除第一个之外的所有子节点。

issuelist = root.findall('//Issuelist')

for issue in issuelist:
    first = True
    for child in issue.getchildren:
       if child.tag is 'Comment' and first is True: 
           First = false
           continue
       if child.tag is 'Comment' and first is False: 
           issue.remove(child)           

etree.tostring(tree)

推荐阅读