【问题标题】:How to append xml file attribute with array value using Python?如何使用 Python 将 xml 文件属性附加到数组值?
【发布时间】:2021-06-14 16:03:35
【问题描述】:

我有一个 xml 文件。

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

我想将此数组附加到上面的 XML 文件中。

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)

m的值是这样的:

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

我想将这些数组附加到我的 XML 中。所以我的期望基于上面的数组,我将追加 2 个新元素。如果数组有 4 则创建新的 4 元素。 这是我的期望输出:

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

任何人都可以给我一个想法和帮助,拜托。我真的很感激。

【问题讨论】:

    标签: python arrays xml append write


    【解决方案1】:

    Jack 的方法似乎更简单,这是另一种方法,包括您需要的 cmets:

    1. 使用解析器读取文件以保留 cmets
    2. 使用 ET.Comment() 插入 cmets
    3. 遍历字典列表并将子元素添加到 xml
    4. 使用toprettyxml() 将xml 转换为格式化字符串,但这会增加不必要的换行符
    5. 使用列表理解和strip() 删除多余的换行符
    6. 在 xml 声明中添加编码信息
    7. 写入原始文件
    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()
    

    我的意见

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

    我的输出

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

    【讨论】:

      【解决方案2】:

      有几种方法可以实现,但我个人更喜欢这种方法:

      from lxml import etree
      
      sd = """your xml above"""
      memos = [[{'location': 'DIMM1', 'banklabel': 'ChannelA', 'cap': '8589934592'}],
      [{'location': 'DIMM2', 'banklabel': 'ChannelB', 'cap': '123456'}]]
      #I changed the second list a bit just to make the example clearer
      
      doc = etree.XML(sd.encode())
      destination = doc.xpath('//process')[0]
      
      parent = """<unitmemory>"""
      
      for mem in memos:
              attr_vals = [list(m.values()) for m in mem][0]
              new_child = f"""<module location="{attr_vals[0]}">
                     <banklabel tool="banklabel">
                          <value type="string">{attr_vals[1]}</value>
                     </banklabel>
                     <cap tool="cap">
                          <value type="string">{attr_vals[2]}</value>
                     </cap>
                </module>"""
              parent+=new_child
      
      parent += """</unitmemory>"""
      new_node = etree.fromstring(parent)
      destination.addnext(new_node)
      print(etree.tostring(doc).decode())
      

      输出是您的预期输出。

      【讨论】:

      • 嗨@Jack Fleeting 谢谢。但它返回此错误doc = etree.XML(sd.encode()) lxml.etree.XMLSyntaxError: Start tag expected, '&lt;' not found, line 1, column 1
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-20
      • 2010-10-03
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      • 2013-10-27
      相关资源
      最近更新 更多