1. Python通过ElementTree操作XML

[success] 介绍说明: 首先,python处理XML文件有三种方法:

  1. SAX(简单的XML for XML)
  2. DOM(文档对象模型)
  3. ElementTree(元素树)

本文中所有操作均通过第三种ElementTree来实现,且因本人能力有限,文中没有对python处理XML文件的深度解读,仅包含日常方法的使用。


ElementTree所有的操作都是基于对 Element对象 来实现的。

处理的XML文件vm.xml(虚拟机XML的部分)

<domain xmlns:ns0="http://ovirt.org/vm/tune/1.0" xmlns:ns1="http://ovirt.org/vm/1.0" type="kvm">
    <name>mrq</name>
    <uuid>e6560851-f62a-4cc0-bb70-261d58a8681f</uuid>
    <memory>2097152</memory>
    <currentMemory>2097152</currentMemory>
    <maxMemory slots="16">8388608</maxMemory>
    <vcpu current="1">2</vcpu>
    <sysinfo type="smbios">
        <system>
            <entry name="manufacturer">oVirt</entry>
            <entry name="product">OS-NAME:</entry>
            <entry name="version">OS-VERSION:</entry>
            <entry name="serial">HOST-SERIAL:</entry>
            <entry name="uuid">e6560851-f62a-4cc0-bb70-261d58a8681f</entry>
        </system>
    </sysinfo>
    <clock adjustment="0" offset="variable">
        <timer name="rtc" tickpolicy="catchup" />
        <timer name="pit" tickpolicy="delay" />
        <timer name="hpet" present="no" />
    </clock>
    <metadata>
        <ns0:qos />
        <ns1:vm>
            <minGuaranteedMemoryMb type="int">2048</minGuaranteedMemoryMb>
            <clusterVersion>4.2</clusterVersion>
            <ns1:custom />
            <ns1:device mac_address="00:1a:4a:16:01:01">
                <ns1:custom />
            </ns1:device>
            <ns1:device devtype="disk" name="sda">
                <ns1:poolID>91954f62-41ec-11e8-842f-0ed5f89f718b</ns1:poolID>
                <ns1:volumeID>c25fc280-420a-11e8-842f-0ed5f89f718b</ns1:volumeID>
                <ns1:imageID>c3ef4edc-3a44-11e8-b467-0ed5f89f718b</ns1:imageID>
                <ns1:domainID>701ce8c8-41f5-11e8-842f-0ed5f89f718b</ns1:domainID>
            </ns1:device>
            <launchPaused>false</launchPaused>
            <resumeBehavior>auto_resume</resumeBehavior>
        </ns1:vm>
    </metadata>
</domain>

演示代码的层级结构

层级.png

解析

import os
import xml.etree.ElementTree as ET

theXML = theXML = os.path.join(os.path.dirname(__file__), 'vm.xml')
tree = ET.parse(theXML)  # 在此次范例中,数据从文件中导入
#  另一种方法为从字符串中导入   
#  tree = ET.fromstring("""XML string""")

从字符串导入有大坑: 如果字符串是单标签如下会报错 \\

输出一下tree, 可以看到是一个ElementTree对象。

In[3]: print(tree)
<xml.etree.ElementTree.ElementTree object at 0x7f5197485a90>

那么为了调试方便,如何展示ElementTree对象呢

In[4]: print(ET.dump(tree))
<domain xmlns:ns0="http://ovirt.org/vm/tune/1.0" xmlns:ns1="http://ovirt.org/vm/1.0" type="kvm">
    <name>mrq</name>
    <uuid>e6560851-f62a-4cc0-bb70-261d58a8681f</uuid>
    <memory>2097152</memory>
    <currentMemory>2097152</currentMemory>
    ...

匹配规则是基于xpath语法,所以你必须对xpath有所了解。(比起bs4,我个人认为xpath更值得掌握,它在爬虫方面功效卓绝且应用范围更广。) 你必须知道,一条标准标签语句,可以解析为

  • 标签名(tag, 解析结果为string)
  • 属性(attrib, 解析结果为标准字典格式 { 'attribName': 'attribValue'})
  • 值 (text, 解析结果为string )

1.1. 查找和修改元素

普通标签元素: 需要注意的是:xml中不支持int型,需要先修改为string型

In[8]: vcpu = tree.find('.//vcpu')  # find element
  ...: print(vcpu.tag, vcpu.attrib, vcpu.text)
  ...: 
  ...: tree.find('.//vcpu').text = str(3)  # chang element
  ...: tree.write(theXML)
  ...: 
vcpu {'current': '1'} 3

命名空间元素:命名空间一般定义在XML文件的首行,该范例中有两个

xmlns:ns0="http://ovirt.org/vm/tune/1.0" xmlns:ns1="http://ovirt.org/vm/1.0"

In[11]: vm = tree.find('metadata').find('{http://ovirt.org/vm/1.0}vm')
   ...: vmDisk = vm.find('{http://ovirt.org/vm/1.0}device[@devtype="disk"]').attrib['name']  # find element
   ...: print(vmDisk)
   ...: # chang vmDiskPoolID
   ...: vm.find('{http://ovirt.org/vm/1.0}device[@devtype="disk"]/').text = "mrq0test-41ec-11e8-842f-0ed5f89f718b"
   ...: tree.write(theXML)
sda

1.2. 添加和删除元素

添加本质是生成新的Element对象,有两种方法可以实现:

  1. 将字符串转化为Element对象
  2. 利用ET.Element(), ET.SubElement()来生成

我将利用 第一种 方法来添加 普通标签元素第二种 方法来添加 命名空间元素 。 普通标签元素:

In[14]: root = tree.getroot()  # convent ElementTree object to Element object
   ...: # delete the vm name
   ...: name = tree.find('.//name')
   ...: root.remove(name)
   ...: 
   ...: # add the vm name
   ...: name = ET.fromstring("""<name> It's hard for me to write a blog -_-</name>""")
   ...: root.insert(0, name)
   ...: tree.write(theXML)

命名空间元素: 一般来说用如果添加XML块, ET.Element(标签名, {属性}) ET.SubElement(父节点, 标签名, {属性}).text = 值

In[15]: # metadata add a disk 
   ...: vm = tree.find('metadata').find('{http://ovirt.org/vm/1.0}vm')
   ...: devices_s = ET.Element('{http://ovirt.org/vm/1.0}device', **{'devtype': 'disk', 'name': "sdb"})
   ...: ET.SubElement(devices_s, '{http://ovirt.org/vm/1.0}poolID').text = "haha"
   ...: ET.SubElement(devices_s, '{http://ovirt.org/vm/1.0}volumeID').text = "hehe"
   ...: ET.SubElement(devices_s, '{http://ovirt.org/vm/1.0}imageID').text = "heihei"
   ...: ET.SubElement(devices_s, '{http://ovirt.org/vm/1.0}domainID').text = "houhou"
   ...: 
   ...: vm.insert(-2, devices_s)
   ...: tree.write(theXML)

删除参考普通标签元素的操作。

results matching ""

    No results matching ""

    results matching ""

      No results matching ""