Python:从XML文件中查找和删除子项并输出到新文件

时间:2015-10-06 13:38:43

标签: python xml

下面有一个XMl文件。我希望能够删除所有未被称为john的子计划并输出到新文件。

    <data>
        <plan_main>
            <plan>
               <name>John</name>
               <id>1</id>
            </plan>
            <plan>
               <name>Charlie</name>
               <id>2</id>
            </plan>
         </plan_main>
       <location>
            <country>
               <code>GB</code>
            </country>
            <country>
               <code>DE</code>
            </country>
       </location>
    </data>

我已经尝试了以下代码,但获得了ValueError Not in list

for plan in root.findall('./plan_main/plan'):
  name = plan.find('name').text
  if name =! "john":
    root.remove(plan)

tree.write('output.xml')

我希望我的输出文件看起来像这样:

       <data>
        <plan_main>
            <plan>
               <name>John</name>
               <id>1</id>
            </plan>
         </plan_main>
       <location>
            <country>
               <code>GB</code>
            </country>
            <country>
               <code>DE</code>
            </country>
       </location>
    </data>

但是我收到以下错误:

     ValueError: list.remove(x): x not in list

1 个答案:

答案 0 :(得分:2)

假设=!只是一个复制/粘贴错误。问题是您尝试使用Element.remove()方法从root节点中删除元素,但.remove()只会删除root的直接子元素。

如果您想使用ElementTree本身,可以将XPath更改为循环遍历所有plan_main元素,然后针对每个plan_main元素循环遍历其所有子元素,并且如果有任何孩子的姓名不是john,请将其删除。实施例 -

for plan_main in root.findall('./plan_main'):
    for plan in plan_main:
        name = plan.find('name').text
        if name.lower() != "john":
            plan_main.remove(plan)

演示 -

>>> import xml.etree.ElementTree as ET
>>> s = """    <data>
...         <plan_main>
...             <plan>
...                <name>John</name>
...                <id>1</id>
...             </plan>
...             <plan>
...                <name>Charlie</name>
...                <id>2</id>
...             </plan>
...          </plan_main>
...        <location>
...             <country>
...                <code>GB</code>
...             </country>
...             <country>
...                <code>DE</code>
...             </country>
...        </location>
...     </data>"""
>>> root = ET.fromstring(s)
>>> for plan_main in root.findall('./plan_main'):
...     for plan in plan_main:
...         name = plan.find('name').text
...         if name.lower() != "john":
...             plan_main.remove(plan)
...
>>> print(ET.tostring(root).decode('utf-8'))
<data>
        <plan_main>
            <plan>
               <name>John</name>
               <id>1</id>
            </plan>
            </plan_main>
       <location>
            <country>
               <code>GB</code>
            </country>
            <country>
               <code>DE</code>
            </country>
       </location>
    </data>

如果您可以使用lxml.etree,则可以使用.getparent()方法获取要删除的子项的直接父级,从而对代码进行少量更改以使其正常工作。示例 -

for plan in root.findall('./plan_main/plan'):
    name = plan.find('name').text
        if name.lower() != "john":
            plan.getparent().remove(plan)