How to append xml file attribute with array value using Python?

I have an xml file.

<?xml version='1.0' encoding='utf-8'?>
<systemdata>
     <process>
          <number code="hsfg" class="hgdgf" tool="gagfa">
               <value type="string" />
               <value type="None" />
          </number>
          <!-- ID -->
          <id code="hsfg" class="gfdg" tool="fadg">
               <value type="string" />
               <value type="None" />
          </id>
     </process>
</systemdata>

I would like to append this array to my XML file above.

memorys = []
for mem in wmiquery.Win32_PhysicalMemory():
    sysmem = {}
    sysmem['location'] = mem.DeviceLocator
    sysmem['banklabel'] = mem.BankLabel
    sysmem['cap'] = mem.Capacity
    memorys.append(sysmem)
for m in memorys:
    print(m)

The value of m is like this:

{'location': 'DIMM1', 'banklabel': 'ChannelA', 'cap': '8589934592'}
{'location': 'DIMM2', 'banklabel': 'ChannelA', 'cap': '8589934592'}

I would like to append these array to my XML. So my expectation based on the array above, I will append 2 new element. If the array has 4 then create new 4 element. Here is my expectation output:

<?xml version='1.0' encoding='utf-8'?>
<systemdata>
     <process>
          <number code="hsfg" class="hgdgf" tool="gagfa">
               <value type="string" />
               <value type="None" />
          </number>
          <!-- ID -->
          <id code="hsfg" class="gfdg" tool="fadg">
               <value type="string" />
               <value type="None" />
          </id>
     </process>
     <!-- memory -->
     <unitmemory>
          <!-- data -->
          <module location="DIMM1">
               <banklabel tool="banklabel">
                    <value type="string">ChannelA</value>
               </banklabel>
               <cap tool="cap">
                    <value type="string">8589934592</value>
               </cap>
          </module>             
          <module location="DIMM2">
               <banklabel tool="banklabel">
                    <value type="string">ChannelA</value>
               </banklabel>
               <cap tool="cap">
                    <value type="string">8589934592</value>
               </cap>
          </module>
     </unitmemory>
</systemdata>

Anyone can give me an idea and help, please. I really appreciated and thankful.

Answer

Jack’s approach seem easier, here is another way including the comments you need:

  1. read your file using a parser to keep comments
  2. insert comments using ET.Comment()
  3. loop through list of dictionaries and add sub-elements to xml
  4. use toprettyxml() to get convert xml to formatted string, but this adds unnecessary new-lines
  5. remove the extra newlines using list comprehension and strip()
  6. add encoding info to xml declaration
  7. write to original file
import xml.etree.ElementTree as ET
import xml.dom.minidom

memorys = [
    {'location': 'DIMM1', 'banklabel': 'ChannelA', 'cap': '100'},
    {'location': 'DIMM2', 'banklabel': 'ChannelB', 'cap': '200'}
]

m_encoding = 'utf-8'
parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True))

tree = ET.parse('sampleXml.xml', parser=parser)
root = tree.getroot()

root.insert(1, ET.Comment('memory'))

unit_mem = ET.SubElement(root, 'unitmemory')
unit_mem.insert(0, ET.Comment('data'))

for mem in memorys:
    m_module = ET.SubElement(unit_mem, 'module ')
    m_module.set('location', mem['location'])

    b_label = ET.SubElement(m_module, 'banklabel  ')
    m_cap = ET.SubElement(m_module, 'cap ')
    b_value = ET.SubElement(b_label, 'value ')
    c_value = ET.SubElement(m_cap, 'value ')

    m_module.set('location', mem['location'])
    b_label.set('tool', 'banklabel')
    m_cap.set('tool', 'cap')
    b_value.set('type', 'string')
    c_value.set('type', 'string')

    b_value.text = mem['banklabel']
    c_value.text = mem['cap']

dom = xml.dom.minidom.parseString(ET.tostring(root))
xml_string = dom.toprettyxml()
xml_string = 'n'.join([line for line in xml_string.splitlines() if line.strip()])
part1, part2 = xml_string.split('?>')

with open("sampleXml.xml", 'w') as xfile:
    xfile.write(part1 + 'encoding="{}"?>n'.format(m_encoding) + part2)
    xfile.close()

My input

{'location': 'DIMM1', 'banklabel': 'ChannelA', 'cap': '100'}
{'location': 'DIMM2', 'banklabel': 'ChannelB', 'cap': '200'}

My output

<?xml version="1.0" encoding="utf-8"?>

<systemdata>
    <process>
        <number code="hsfg" class="hgdgf" tool="gagfa">
            <value type="string"/>
            <value type="None"/>
        </number>
        <!-- ID -->
        <id code="hsfg" class="gfdg" tool="fadg">
            <value type="string"/>
            <value type="None"/>
        </id>
    </process>
    <!--memory-->
    <unitmemory>
        <!--data-->
        <module location="DIMM1">
            <banklabel tool="banklabel">
                <value type="string">ChannelA</value>
            </banklabel>
            <cap tool="cap">
                <value type="string">100</value>
            </cap>
        </module>
        <module location="DIMM2">
            <banklabel tool="banklabel">
                <value type="string">ChannelB</value>
            </banklabel>
            <cap tool="cap">
                <value type="string">200</value>
            </cap>
        </module>
    </unitmemory>
</systemdata>

Leave a Reply

Your email address will not be published. Required fields are marked *