J'essaie d'utiliser l'arborescence des éléments pour localiser un élément d'intérêt à partir d'un XML et supprimer le groupe entier (c'est-à-dire le parent) du 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

Ce code identifie l'élément et obtient le parent de l'élément que je souhaite supprimer. Ensuite, cela me donne une erreur lorsque j'essaye de supprimer l'élément:

ValueError: Element is not a child of this node.

Le XML en question est assez compliqué. Voici un extrait:

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

Il existe de nombreux groupes de paramètres «FitItem». J'essaye de localiser celui avec «[V18]» et «Paramètre = V» et de supprimer tout le FitItem. Quelqu'un saurait-il comment faire cela?

Merci

0
CiaranWelsh 11 juil. 2015 à 17:24

2 réponses

Meilleure réponse

Si le XML publié n'est qu'une partie d'un XML plus grand et que <ParameterGroup name="FitItem"> n'est pas réellement l'élément racine, vous devriez pouvoir supprimer l'élément référencé par la variable parent de son parent (ne soyez pas confus) ainsi :

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

Sinon, vous ne pouvez pas supprimer parent car il fait référence à l'élément racine, et le document XML nécessite exactement un élément racine pour rester qualifié comme XML.

Voici un exemple fonctionnel de démonstration:

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)

sortie:

<root>
    </root>
1
har07 11 juil. 2015 à 15:57

Une fois que j'ai appris BeautifulSoup, je ne retourne jamais utiliser etree.

Remarque:

  1. J'ai ajouté le copasiML racine dans votre XML en fonction du commentaire
  2. J'ai ajouté un autre FitItem avec datafireball comme texte juste pour montrer que nous localisons le bon élément à la fin.
  3. Dans BeautifulSoup, j'ai utilisé deux approches pour localiser l'élément find(lamda), find(args..), car vous avez pas mal de règles localisant FitItem alors que votre logique de recherche parent est assez simple.

Voici le code:

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()

Voici la sortie:

<?xml version="1.0" encoding="utf-8"?>
<ParameterGroup name="copasiML">
 <ParameterGroup name="FitItem">
  Datafireball
 </ParameterGroup>
</ParameterGroup>
1
B.Mr.W. 11 juil. 2015 à 15:35