使用 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了。
注:
- 我根据评论
添加了根 copasiML 到你的 XML
- 我添加了另一个带有 datafireball 的 FitItem 作为文本只是为了显示我们定位
最后是正确的元素。
- 在 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>
我正在尝试使用元素树从 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了。
注:
- 我根据评论 添加了根 copasiML 到你的 XML
- 我添加了另一个带有 datafireball 的 FitItem 作为文本只是为了显示我们定位 最后是正确的元素。
- 在 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>