2

I have some lines of XML from where I need to parse and extract the species names for the list of reactions and products, so far I have tried with the following lines but I wonder if there's a way I can do it more clearly

XML:

<?xml version="1.0" encoding="UTF-8"?>
<sbml xmlns="data" level="2" version="1">
  <model id="E" name="core_model">
    <notes>
    <listOfUnitDefinitions>
    <listOfCompartments>
    <listOfSpecies>
    <listOfReactions>
      <reaction id="ID_1" name="name_1">
        <notes>
        <listOfReactants>
          <speciesReference species="react_1_1"/>
          <speciesReference species="react_2_1"/>
          <speciesReference species="react_3_1"/>
        </listOfReactants>
        <listOfProducts>
          <speciesReference species="produ_1_1"/>
          <speciesReference species="produ_2_1"/>
          <speciesReference species="produ_3_1"/>
        </listOfProducts>
        <kineticLaw>
      </reaction>
      <reaction id="ID_2" name="name_2">
        <notes>
        <listOfReactants>
          <speciesReference species="react_1_2"/>
        </listOfReactants>
        <listOfProducts>
          <speciesReference species="produ_1_2"/>
        </listOfProducts>
        <kineticLaw>
      </reaction>
      <reaction id="ID_3" name="name_3">
        <notes>
        <listOfReactants>
          <speciesReference species="react_1_3"/>
          <speciesReference species="react_2_3"/>
        </listOfReactants>
        <listOfProducts>
          <speciesReference species="produ_1_3"/>
          <speciesReference species="produ_2_3"/>
        </listOfProducts>
        <kineticLaw>
      </reaction>
    </listOfReactions>
  </model>
</sbml>

Python:

import xml.etree.ElementTree as et
tree = et.parse('example.xml')
root = tree.getroot()
child = root[0]

for x in child[4]: #to get the list of REACTIONS ids and names
    print (x.get('id'),':',x.get('name'))

for h in range(2): #gives back the list of species for reactants and products
    for i in range(2):
        for x in child[4][h][i+1]:
            print(x.get('species'))

Prints:

react_1_1
react_2_1
react_3_1
produ_1_1
produ_2_1
produ_3_1
react_1_2
produ_1_2

Desired Output

ID_1
Reactants
react_1_1
react_2_1
react_3_1
Products
produ_1_1
produ_2_1
produ_3_1

ID_2
Reactions
react_1_2
Products
produ_1_2
.
.
.

with the python code I can parse and extract the names of the species but the output is a list without distinction between reactions and products, I have also tried with element.iter() but was unsuccesful

Alex
  • 29
  • 6
  • Use xpath: https://stackoverflow.com/questions/8692/how-to-use-xpath-in-python – kutschkem Feb 17 '20 at 14:20
  • 1
    I am pretty sure *efficient* means simpler in this case. If however it was a really big xml file and if your concern was more about CPU/RAM usage, https://docs.python.org/3/library/xml.sax.reader.html parsing can be helpful. – JL Peyret Feb 17 '20 at 16:09
  • 1
    Your xml is invalid; can you edit your question to fix it? – Jack Fleeting Feb 17 '20 at 17:26
  • I've edited the xml, your help will be much appreciated – Alex Feb 19 '20 at 11:13

1 Answers1

2

Another method.

from simplified_scrapy import SimplifiedDoc,utils
html = utils.getFileContent('example.xml')
doc = SimplifiedDoc(html)
reactions = doc.listOfReactions.reactions
for reaction in reactions:
  print (reaction['id'],reaction['name']) # to get the list of REACTIONS ids and names
  # gives back the list of species for reactants and products
  print ('Reactants')
  print (reaction.selects('listOfReactants>speciesReference>species()'))
  print ('Products')
  print (reaction.selects('listOfProducts>speciesReference>species()'))

Result:

ID_1 name_1
Reactants
['react_1_1', 'react_2_1', 'react_3_1']
Products
['produ_1_1', 'produ_2_1', 'produ_3_1']
ID_2 name_2
Reactants
['react_1_2']
Products
['produ_1_2']
ID_3 name_3
Reactants
['react_1_3', 'react_2_3']
Products
['produ_1_3', 'produ_2_3']

Here are more examples: https://github.com/yiyedata/simplified-scrapy-demo/tree/master/doc_examples

dabingsou
  • 2,469
  • 1
  • 5
  • 8