使用Etree从XML中删除特定元素

时间:2015-07-11 14:24:20

标签: python xml elementtree

我正在尝试使用Element树从XML中定位感兴趣的元素,并从XML中删除整个组(即父组)。

import xml.etree.ElementTree as ET
from lxml import etree 

copasiML_str= IA.read_copasiML_as_string(model_file) # Reads XML as string
copasiML=ET.fromstring(copasiML_str) # parse XML to etree

for i in copasiML.findall(".//*[@name='ObjectCN']"): # locate element 
    if '[v18]' in  i.attrib['value']:           #search for 'v18' 
        if 'Parameter=V' in i.attrib['value']:   #search for 'Parameter=V'
            print i.attrib['value']             #Element identified
            parent = i.getparent()   #gets the parent of identified
            copasiML.remove(parent) # This does not work

此代码标识元素并获取我要删除的元素的父元素。然后,当我尝试删除元素时,它会给我一个错误:

ValueError: Element is not a child of this node.

有问题的XML相当复杂。这是一个片段:

<ParameterGroup name="FitItem">
            <ParameterGroup name="Affected Cross Validation Experiments">
            </ParameterGroup>
            <ParameterGroup name="Affected Experiments">
              <Parameter name="Experiment Key" type="key" value="Experiment_1"/>
              <Parameter name="Experiment Key" type="key" value="Experiment_2"/>
              <Parameter name="Experiment Key" type="key" value="Experiment_4"/>
            </ParameterGroup>
            <Parameter name="LowerBound" type="cn" value="1e-06"/>
            <Parameter name="ObjectCN" type="cn" value="CN=Root,Model=NoName,Vector=Reactions[V18],ParameterGroup=Parameters,Parameter=V,Reference=Value"/>
            <Parameter name="StartValue" type="float" value="0.1852208634119804"/>
            <Parameter name="UpperBound" type="cn" value="100"/>
          </ParameterGroup>

有许多'FitItem'参数组。我正试图找到一个'[V18]'和'Parameter = V'并删除整个FitItem。有人会知道怎么做吗?

由于

2 个答案:

答案 0 :(得分:1)

如果发布的XML只是更大的XML的一部分,并且<ParameterGroup name="FitItem">实际上不是根元素,那么您应该能够删除parent变量引用的元素&#39;父母(不要感到困惑),如下:

......
parent = i.getparent()
parent.getparent().remove(parent)

否则,您无法删除parent,因为它引用了根元素,而XML文档只需要一个根元素就可以保留为XML格式。

这是演示的一个工作示例:

from lxml import etree

xml = '''<root>
    <ParameterGroup name="FitItem">
            <ParameterGroup name="Affected Cross Validation Experiments">
            </ParameterGroup>
            <ParameterGroup name="Affected Experiments">
              <Parameter name="Experiment Key" type="key" value="Experiment_1"/>
              <Parameter name="Experiment Key" type="key" value="Experiment_2"/>
              <Parameter name="Experiment Key" type="key" value="Experiment_4"/>
            </ParameterGroup>
            <Parameter name="LowerBound" type="cn" value="1e-06"/>
            <Parameter name="ObjectCN" type="cn" value="CN=Root,Model=NoName,Vector=Reactions[V18],ParameterGroup=Parameters,Parameter=V,Reference=Value"/>
            <Parameter name="StartValue" type="float" value="0.1852208634119804"/>
            <Parameter name="UpperBound" type="cn" value="100"/>
          </ParameterGroup>
</root>'''
copasiML=etree.fromstring(xml)
query = "//*[@name='ObjectCN'][contains(@value,'[V18]')][contains(@value,'Parameter=V')]"
for i in copasiML.xpath(query):
    parent = i.getparent()
    parent.getparent().remove(parent)

print etree.tostring(copasiML)

输出

<root>
    </root>

答案 1 :(得分:1)

一旦我学会BeautifulSoup,我就再也不会使用etree了。

注意:

  1. 我根据评论
  2. 将根copasiML添加到您的XML中
  3. 我添加了另一个带有datafireball的FitItem作为文本,以显示我们找到的位置 最终的正确要素。
  4. 在BeautifulSoup中,我使用了两种方法来定位元素find(lamda)find(args..),因为您有很多规则定位FitItem,而您的查找父逻辑非常简单。
  5. 以下是代码:

    from bs4 import BeautifulSoup
    myString = """
    <ParameterGroup name="copasiML">
    <ParameterGroup name="FitItem">
        <ParameterGroup name="Affected Cross Validation Experiments"></ParameterGroup>
        <ParameterGroup name="Affected Experiments">
          <Parameter name="Experiment Key" type="key" value="Experiment_1"/>
          <Parameter name="Experiment Key" type="key" value="Experiment_2"/>
          <Parameter name="Experiment Key" type="key" value="Experiment_4"/>
        </ParameterGroup>
        <Parameter name="LowerBound" type="cn" value="1e-06"/>
        <Parameter name="ObjectCN" type="cn" value="CN=Root,Model=NoName,Vector=Reactions[V18],ParameterGroup=Parameters,Parameter=V,Reference=Value"/>
        <Parameter name="StartValue" type="float" value="0.1852208634119804"/>
        <Parameter name="UpperBound" type="cn" value="100"/>
    </ParameterGroup>
    <ParameterGroup name="FitItem">Datafireball</ParameterGroup>
    </ParameterGroup>
    """
    soup = BeautifulSoup(myString, "xml")
    
    def myfunc(e):
        try:
            if (e['name'] == 'ObjectCN') and (e.name == 'Parameter') and ('V18' in e['value']):
                return True
            else: 
                return False
        except:
            return False
    
    target = soup.find(lambda x: myfunc(x))
    parent = target.find_parent('ParameterGroup', {'name':'FitItem'})
    parent.decompose()
    
    print soup.prettify()
    

    这是输出:

    <?xml version="1.0" encoding="utf-8"?>
    <ParameterGroup name="copasiML">
     <ParameterGroup name="FitItem">
      Datafireball
     </ParameterGroup>
    </ParameterGroup>