【问题标题】:Removing specific elements from XML using Etree使用 Etree 从 XML 中删除特定元素
【发布时间】:2015-07-11 14:24:19
【问题描述】:

我正在尝试使用元素树从 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 相当复杂。这是一个sn-p:

<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。有人知道该怎么做吗?

谢谢

【问题讨论】:

  • 抱歉,粘贴错误。根称为 copasiML。
  • 鉴于该示例 XML,*[@name='ObjectCN'] 的父元素是根元素,这意味着您正在尝试删除整个 XML,这将使其不是格式良好的 XML
  • 请重新检查,我怀疑在实际代码中您使用lxml(etree.fromstring() 或类似)代替填充copasiML 变量,因为内置ElementTree 没有方法@ 987654329@

标签: python xml elementtree


【解决方案1】:

如果发布的 XML 只是较大 XML 的一部分并且 &lt;ParameterGroup name="FitItem"&gt; 实际上不是根元素,您应该能够从它的父元素中删除 parent 变量引用的元素(不要混淆),例如所以:

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

【讨论】:

  • 嗨 har07。我虽然这样的事情应该可以工作,但是我得到一个 AttributeError: 'builtin_function_or_method' object has no attribute 'remove'
  • @user3059024 为我工作,尝试运行演示代码
  • 旁注:BS 是一种可能的替代方案,但通常并不比 lxml 更好。 stackoverflow.com/questions/31351856/…
  • 你的策略奏效了。我所做的唯一更改是匹配 'value' 的整个值(即 CN=Root,Model=NoName,Vector=Reactions[V18],ParameterGroup=Parameters,Parameter=V,Reference=Value"/>)并且它有效. 感谢您的帮助。非常感谢。
【解决方案2】:

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

注意:

  1. 我根据评论将根 copasiML 添加到您的 XML 中
  2. 我添加了另一个带有 datafireball 的 FitItem 作为文本,只是为了显示我们定位 最后的正确元素。
  3. 在 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>

【讨论】:

  • 您好 B.MR.W,感谢您的回复。我尝试了你的代码,似乎 soup.findall 函数没有找到任何东西(它返回'None')
  • @user3059024 使用 find 或 find_all
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 2018-05-12
  • 1970-01-01
  • 2012-09-06
  • 1970-01-01
相关资源
最近更新 更多