【问题标题】:How to delete a particular line in xml file based on the condition using python?如何使用python根据条件删除xml文件中的特定行?
【发布时间】:2015-08-05 09:40:25
【问题描述】:

我有一个问题,正在寻找解决方案。

我想根据条件删除该行。例如 xml 文件是

<app>
    .
    .
<process>
    <tag>any tag</tag>
    <trigger order="1" name="activity1" perform="y">
        <external>
                <action name="check_req"/>
                <action name="event"/>
        </external>
        <var name="type"/>
        <var name="user" />
          </trigger>
</process>
<process>
<tag>any tag</tag>
<trigger order="3" name="activity1" perform="y">
    <external>
            <action name="check_req"/>
            <action name="event"/>
            <action name="ckeck"/>
        </external>
        <var name="type"/>
        <var name="user" />
          </trigger>
</process>
<process>
<tag>any tag</tag>
<trigger order="2" name="activity1" perform="y">
    <external>
            <action name="event"/>
            <action name="ckeck"/>
        </external>
        <var name="type"/>
        <var name="user" />
          </trigger>
</process>
<process>
<tag>any tag</tag>
  <trigger order="1" name="activity1" perform="y">
    <external>
            <action name="check_req"/>
            <action name="event"/>
            <action name="ckeck"/>
        </external>
        <var name="type"/>
        <var name="user" />
     </trigger>
</process>
<process>
   <tag>any tag</tag>
   <trigger order="4" name="activity1" perform="y">
    <external>
            <action name="ckeck"/>
            <action name="check_req"/>
        </external>
        <var name="type"/>
        <var name="user" />
   </trigger>
</process>
</app>

所以我想从这段代码中删除&lt;action name="ckeck"/&gt;这行,只要在触发器中出现这两个动作

<action name="ckeck"/> 
<action name="ckeck_req"/>

<action name="ckeck_req"/>
<action name="ckeck"/>

所以我必须删除行 &lt;action name="ckeck"/&gt; 只有在上述两个动作同时发生的情况下,否则它不会删除任何行。

所以我是 python 语言的新手,所以我无法做这件事。问题在于该文件包含许多触发块,其中一些既包含动作块,又包含仅一个动作块。特定的行是仅当给定情况发生时才删除

【问题讨论】:

  • 表示如果下一个标签是&lt;action name="ckeck_req"/&gt;,则必须删除&lt;action name="ckeck"/&gt; 标签?
  • 可以是任意顺序。动作顺序不固定。在这两个动作之间也可以有许多动作块。

标签: python python-2.7 python-3.x subprocess


【解决方案1】:

您应该使用一些 xml 解析库,例如 xml.etree.ElementTreelxml

然后你可以使用XPATH找到&lt;trigger&gt;下的所有&lt;external&gt;元素,然后得到action元素的name属性为check_reqaction元素的name属性如 ckeck 。然后,如果两者都不是,这意味着两个孩子都存在,删除名称属性为ckeck 的元素,然后将 xml 保存回其他文件(甚至同一个文件)。示例 -

import xml.etree.ElementTree as ET
file = ET.parse('a.xml')
root = file.getroot()
for elem in root.findall('.//trigger/external'):
    check_req_elems = elem.find('./action[@name="check_req"]')
    check_elem = elem.find('./action[@name="ckeck"]')
    if check_req_elems is not None and check_elem is not None:
            elem.remove(check_elem)

file.write('b.xml')

示例/演示 -

我的a.xml -

<app>
<process>
<tag>any tag</tag>
<trigger order="3" name="activity1" perform="y">
    <external>
            <action name="check_req"/>
            <action name="event"/>
            <action name="ckeck"/>
        </external>
        <var name="type"/>
        <var name="user" />
          </trigger>
</process>>
<process>
<tag>any tag</tag>
<trigger order="2" name="activity1" perform="y">
    <external>
            <action name="event"/>
            <action name="ckeck"/>
        </external>
        <var name="type"/>
        <var name="user" />
          </trigger>
</process>
</app>

代码-

>>> file = ET.parse('a.xml')
>>> root = file.getroot()
>>> for elem in root.findall('.//trigger/external'):
...     check_req_elems = elem.find('.//action[@name="check_req"]')
...     check_elem = elem.find('.//action[@name="ckeck"]')
...     if check_req_elems is not None and check_elem is not None:
...             elem.remove(check_elem)
...
>>> file.write('b.xml')

我的b.xml 变成了-

<app>
<process>
<tag>any tag</tag>
<trigger name="activity1" order="3" perform="y">
    <external>
            <action name="check_req" />
            <action name="event" />
            </external>
        <var name="type" />
        <var name="user" />
          </trigger>
</process>
<process>
<tag>any tag</tag>
<trigger name="activity1" order="2" perform="y">
    <external>
            <action name="event" />
            <action name="ckeck" />
        </external>
        <var name="type" />
        <var name="user" />
          </trigger>
</process>
</app>

【讨论】:

  • 谢谢,您的解决方案对我有用。并学习有关 XML 解析的新知识。
  • 嗨@Anand,此解决方案正在删除 xml 文件中显示的 cmets。请您提出任何不会删除 cmets 的解决方案。
  • 您可以在这里查看 XMLParser - effbot.org/zone/element-pi.htm (PIParser) ,它会将 cmets 保留在您的 xml 中。试试看(在上面的 ET.parse() 函数中使用这个解析器。
  • 我在这里查看了 XMLParser - [link](effbot.org/zone/element-pi.htm) (PIParser)。它确实适用于 ElementTree 1.2.X。但是我有最新的,所以我不能回滚到 1.2。
  • 不能用最新的代码?你有任何错误吗?
【解决方案2】:

当两个动作出现在一个触发器中时,它们是否总是以相同的方式排序,即“ckeck_req”之后的“ckeck”并且相隔一行?如果是这种情况,您可以基于此给出条件,例如

action1 = "ckeck_req"
action2 = "ckeck"
with open(xmlfile, "r") as f:
    x = f.readlines()
y = [] # new list without the unwanted actions
for i in range(len(x)):
    if action2 in x[i] and action1 in x[i-2]:
        continue
    else:
        y.append(x[i])

然后您将新列表 y 写入文件。我只是在脑海中写下了这一点,所以很可能有更好的方法来做到这一点。既然我想了想,你可能想看看Regular Expressions

【讨论】:

  • 像处理基于行的文本文件一样处理 XML 文件并不是一个好主意,因为它们不是。例如,同一个 XML 文档可能只格式化为一行。
猜你喜欢
  • 1970-01-01
  • 2020-07-24
  • 2022-06-15
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多