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

Removing specific elements from XML using Etree

我正在尝试使用元素树从 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。有人知道该怎么做吗?

谢谢

如果发布的 XML 只是更大的 XML 的一部分并且 <ParameterGroup name="FitItem"> 实际上不是根元素,您应该能够删除 [=14 引用的元素=] 来自它的父变量(不要混淆)像这样:

......
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>

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

注:

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

代码如下:

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>