Python入门教程-11 xml解析(minidom)

1. 概述

XML解析是软件开发中经常会遇到的事情,包括C++、Java,以及Python等(此外的语言基本无涉及微笑)。C/C++比较经典的就是libxml2(http://www.xmlsoft.org/),Java有SDK(参考Core Java),而Python有几个库,但通常使用xml.dom.minidom就基本可以满足日常工作了。


本文就是讨论xml.dom.minidom的常用方法。


1.1 libxml2

Linux下面也有libxml2库可用,而在Windows上面,就需要单独去下载libxml2。


2. 参考资料

minidom的参考资料主要如下:

  • https://docs.python.org/3/library/xml.dom.minidom.html:使用方法及示例
  • hg.python.org/cpython/file/3.4/Lib/xml/dom/minidom.py:minidom的源代码,可以查到所有的方法和属性


3. 常用操作步骤

无论哪种语言,对于xml的解析基本上步骤都是类似的,——毕竟处理的是完全相同的XML语法。


3.1 参考步骤

对于minidom来讲,通常是如下几个步骤:

1. 调用parse()方法把xml文件加载到内存,形成DOM对象(树);

2. 调用documentElement()获取根元素,或称整个文档;

3. 调用getElementsByTagName()获取某个节点下面所有特定tag的所有子节点;或者,

4. 调用childNodes来处理子节点;

5. 调用getAttribute()获取节点的特定属性;或者,

6. 如果该节点无任何属性,已到数据层,则调用.data属性取具体的文本串。


3.2 调试手段

当xml层次太多的时候,可能会不确定当前处理的节点是什么,为此可以借助minidom的一些方法进行调试,比如:

  • cur_node.toxml(): 打印当前处理的节点的xml字符串
  • cur_node.nodeName: 打印当前节点的名称
  • 等等


简单地讲,就是从minidom的源代码中去遍历其方法和属性,根据名称即可大致猜测其具体含义。——当然,进一步通过示例代码进一步验证。


4. 示例

在第一个参考资料中,即给出了一个示例代码。这里结合日常学习的实践,再给出一个例子阐述minidom的使用方法。


4.1 下载Android源码的xml解析

4.1.1 需求

这里的例子来源于优化的下载Android源码的Python脚本一文,即通过Android repo/git库的default.xml文件,自动构造git clone命令,从而下载Android的每个git库。

为了提高页面浏览的流畅性,并便于读者调试,default.xml提供的下载池:http://download.csdn.net/detail/u013344915/7347711

首先抛开Android的领域知识,我们简化成如下的(设计)需求:

  • 获取xml文件中的每一个project节点,获取其path属性和name属性的值,即path_attributename_attribute
  • 根据path和name属性,构造一条git命令,即字符串格式为git clone http://android.googlesource.com/name_attribute.gitdownload_dir/path_attribute
  • 其中download_dir是Android下载的目标目录,每个project下载到这个目标目录下面的某个子目录(即path_attribute中);

因为本文首先是阐述xml解析的方法,所以以上需求进一步可以简化为:

  • 获取所有project的path属性和name属性的值

至于如何利用这些属性去构造git命令,以及下载策略等则不再本文讨论。如此通过彻底的简化来突出xml本身的解析方法。


4.1.2 设计

——这里用词“设计”显然有夸大之嫌,但我们姑且用之。

根据前面描述的xml解析的步骤,我们给出如下的设计思路:

1. 把xml加载到内存:dom = minidom.parse("default.xml")

2. 获取根目录:manifest = dom.documentElement ——通过xml文件看到,顶级节点名为manifest,所以这里定义了manifest对象

3. 遍历manifest阶段下面的每一个project节点:projects = manifest.getElementsByTagName("project") ——这里返回的是一个list

4. 或者调用projects = manifest.childNodes属性获取manifest的所有字节点。但因为除了project,还包括remote和default等节点,所以需要剔除掉它们。——因为本文阐述xml解析的方法、讨论可能的属性和方法,所以我们会通过一些bad smell的代码说明问题,但这并不意味着正式项目中需要采用这种策略。

5. 获取project的path和name属性:path_attribute = project.getAttribute("path"), name_attribute = project.getAttribute("name")


4.1.3 Sprint1

作为初始迭代,我们只需要把所有project的两个属性取到、打印到屏幕上即可。

——因为是示例,我们这里并没有考虑可测试性,特别是没有考虑自动化测试的需求,对于打印格式也没有那么严格。

代码如下:

#!/usr/bin/env python

import xml.dom.minidom
import os

default_xml = "./default.xml"
dom = xml.dom.minidom.parse(default_xml)
manifest = dom.documentElement
projects = manifest.getElementsByTagName("project")
for project in projects:
    path = project.getAttribute("path")
    name = project.getAttribute("name")
    print path, name

运行结果:

flying-bird@flyingbird:~/examples/python/minidom$ ./sprint1.py 
build platform/build
abi/cpp platform/abi/cpp
。。。。。。
tools/studio/cloud platform/tools/studio/cloud
tools/swt platform/tools/swt
flying-bird@flyingbird:~/examples/python/minidom$ 

4.1.4 sprint1 with bad smell

下面再用node.childNodes属性完成上述任务:

#!/usr/bin/env python

import xml.dom.minidom
import os

default_xml = "./default.xml"
dom = xml.dom.minidom.parse(default_xml)
manifest = dom.documentElement
children = manifest.childNodes
for child in children:
    tag = child.nodeName
    if tag == "project":
        path = child.getAttribute("path")
        name = child.getAttribute("name")
        print path, name


4.1.5 拼接git命令

如果只关心xml解析,则可以跳过本节。

在利用xml得到了关键信息之后,我们可以逐步再增加功能,这一步即实现git命令。即根据path和name,拼接成可以执行的git命令。根据前面的需求描述,其实就是一个字符串连接而已,代码如下:

#!/usr/bin/env python

import xml.dom.minidom
import os

default_xml = "./default.xml"
dom = xml.dom.minidom.parse(default_xml)
manifest = dom.documentElement
projects = manifest.getElementsByTagName("project")
for project in projects:
    path = project.getAttribute("path")
    name = project.getAttribute("name")
    git_command = "git clone http://android.googlesource.com/" + name + " ./android_source/" + path
    print git_command


运行结果:

flying-bird@flyingbird:~/examples/python/minidom$ ./sprint2.py 
git clone http://android.googlesource.com/platform/build ./android_source/build
。。。。。。。。。。。。。。
git clone http://android.googlesource.com/platform/tools/swt ./android_source/tools/swt
flying-bird@flyingbird:~/examples/python/minidom$ 


5. 局限性

minidom是使用有限的一个xml库,有些功能无法获取CDATA,此时就要选用功能更全的dom库了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值