2015-07-11 3 views
0

Я пытаюсь использовать дерево элементов, чтобы найти интересующий элемент из XML и удалить всю группу (т. Е. Родительскую) из XML.Удаление определенных элементов из XML с помощью Etree

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. Кто-нибудь знает, как это сделать?

Благодаря

+0

К сожалению, это была ошибка склеивание. Корень называется copasiML. – CiaranWelsh

+0

Учитывая, что образец XML, родительский элемент '* [@ name = 'ObjectCN']' является корневым элементом, это означает, что вы пытаетесь удалить весь XML, который сделает его неверным. XML – har07

+0

Пожалуйста, повторите проверку, я подозреваю в самом коде вы используете 'lxml' (' etree.fromstring() 'или аналогичный) вместо того, чтобы заполнить переменную' copasiML', потому что встроенный 'ElementTree' не имеет метода' getparent() ' – har07

ответ

1

Если XML размещена только часть большего XML и <ParameterGroup name="FitItem"> не является на самом деле корневой элемент, вы должны быть в состоянии удалить элемент, на который ссылается 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> 
+0

Hi har07. Я, хотя что-то вроде этого, должен работать, но я получаю объект AttributeError: 'builtin_function_or_method' не имеет атрибута 'remove' – CiaranWelsh

+0

@ user3059024 работал для меня, попробуйте запустить демонстрационный код – har07

+0

Боковое примечание: BS - это возможная альтернатива, но на самом деле лучше, чем lxml в целом. http://stackoverflow.com/questions/31351856/are-there-any-benefits-of-using-beautiful-soup-to-parse-xml-over-using-lxml-alon – har07

1

После того, как я узнал BeautifulSoup, я никогда не вернусь использование использование etree.

Примечание:

  1. Я добавил корневой copasiML в свой XML на основе комментария
  2. я добавил еще один FitItem с datafireball как текст, чтобы показать нам найти правильный элемент в конце.
  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> 
+0

Hi B.MR.W, спасибо за ответ. Я попробовал ваш код, и кажется, что функция soup.findall ничего не находит (ну, он возвращает «None») – CiaranWelsh

+0

@ user3059024 использовать find или find_all –

Смежные вопросы