-1

My xml file is test.xml. See below

<?xml version="1.0" ?>
<Output> 
<partialstore /> <!-- The code writes the spectrum at Sun position for each species on a FITS file (optional) -->
<fullstore />    <!-- The code writes the complete (r,z,p) grid of propagated particles for each species on a FITS file (optional) -->
<feedback value="2" />   </Output>

<Diffusion type="Constant"> <!-- Spatial distribution of the diffusion coefficient; options: Constant, Exp, Qtau -->
<!-- In Constant mode: D(Rigidity)   = beta^etaT * D0 * (Rigidity/4GV)^delta -->
<!-- In Exp mode:      D(Rigidity,z) = beta^etaT * D0 * (Rigidity/4GV)^delta * exp(z/zt) -->
    <D0_1e28 value="2.7" />   <!-- Normalization of the diffusion coefficient at reference rigidity DiffRefRig Unit: 10^28 cm^2/s -->
    <DiffRefRig value = "4" /> <!-- Reference rigidity for the normalization of the diffusion coefficient -->
<!-- NOTE: the reference rigidity 4 GV is stored in the const D_ref_rig defined in include/constants.h --> 
    <Delta value="0.6" />    <!-- Slope of the diffusion coefficient spectrum -->
    <zt value="4" />          <!-- Scale heigth of the diffusion coefficient, useful in Exp mode: D(z) \propto exp(z/zt) (optional) -->
    <etaT value="1." />       <!-- Low energy correction factor of the diffusion coefficient: D \propto beta^etaT  --> </Diffusion>

I want to parse this xml with python. There are two root elements output and diffusion. I want to add 0.6 with D0_1e28 value and Delta_value so that those become 3.1 and 1.2 respectively and save the test.xml as a test_mod.xml with the modification. How can I do it with python code?

  • What you have is not an XML file, since it does not have a single root element. Similar question: https://stackoverflow.com/q/57450461/407651. – mzjn Sep 13 '19 at 11:11

1 Answers1

0

If I understand you correctly, this should work, using xpath with lxml:

xml = """    
<root>
[your xml above; note that it was an invalid xml file, so I added a root]
</root>
"""

import lxml.etree as et
tree = et.fromstring(xml)

to_change = ['//Diffusion/D0_1e28','//Delta'] #those are the items you are changing

for i in range(len(to_change)):
    item=tree.xpath(to_change[i])[0]  #xpath returns a list of 1 item, so [0] selects it
    item.attrib['value']= str(float(item.attrib['value'])+0.6) 
    #the "value" attribute has a value of type 'string' which needs to be cast to 
    #'float' to increment it by 0.6, and then back to 'string` to change the value
    #of the 'value' attribute    

mydata=et.tostring(tree)
with open("test_mod.xml", "wb") as myfile:
    myfile.write(mydata)
Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45
  • Hi Jack Fleeting! It is very close to what I am expecting. I need a little bit help. First I do not understand the first 5 lines (xml = '""" to """). Do I put those lines in the python code or modify the xml file itself? Secondly, the final output (test_mod.xml) should be and <\root> free as it was executed by another program which gives an error if there is any ... <\root> forms. Actually, if i modify my xml by putting ...<\root> then how can I do it with python code so that I can include it in the xml file and also remove those whenever I want? – Sayan Biswas Sep 14 '19 at 05:46
  • I also need to call the xml file repeatedly in my python script. So please give me that command line also so that i can include it in my python code. – Sayan Biswas Sep 14 '19 at 05:57
  • @SayanBiswas - Re your 1st comment: 1st point: you need to add it to the xml file itself, or else lxml won't be able to parse it. 2nd point: - you can remove the tags before writing to file, as in `mydata.replace('',''). I don't really understand your 2nd comment and it sound more like a different question which should be posted separately. – Jack Fleeting Sep 14 '19 at 15:34