DOM说明:
DOM:Document Object Model API
DOM是一种跨语言的XML解析机制,DOM把整个XML文件或字符串在内存中解析为树型结构方便访问。
xml.dom.minidom就是DOM在Python中实现,本文主要结合minidom解释DOM架构。

API导入:

from xml.dom.minidom import parse
from xml.dom.minidom import parseString
import xml.dom.minidom
dom和etree是xml package目录下的两个subpackage,minidom和ElementTree是dom和etree下的两个module文件,以.py后缀,其中定义了一系列的类和方法。
Document.documentElement相当于Etree中的tree.getroot()用于获取整个树唯一的根节点

概念解析:

xml.dom中包含以下类:

1.DOMImplementation
2.Node
Node是最重要的类,XML被解析为一个树,所有的节点都是都是node的子类,这些节点可以是element、comments等等,官网列出的节点类型就有:
ELEMENT_NODE, ATTRIBUTE_NODE, TEXT_NODE, CDATA_SECTION_NODE, ENTITY_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE,DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE,每个节点有一个数字表示,只要是node类型就可以使用node.nodeType来判断他属于哪一种node,例如if child.nodeType==child.ELEMENT_NODE:或者if child.nodeType==1: --两者等价
3.NodeList --通过getElementsByTagName()方法返回的nodelist,此方法只有element和document两个类有。
4.DocumentType
5.Document --整个XML文件解析树,包含所有element、attribute、comments、text等等,也是node的子类。
6.Element
7.Attr --element的属性,这个类型的node只能由Element.getAttributeNode(attrname)来获取,无法遍历获取,而且其既不是element node的子节点也不是兄弟节点。几乎从无必要获取此节点,直接使用element类的getAttribute(attrname)来得到属性的值即可。
8.Comment --comment节点,表示XML文件注释节点
9.Text --xml.etree.ElementTree中的text表示的是element中的内容,而这里的text类型表示一个node,这个node可以是element中的data节点也可以是element之间的换行和制表符(\n\t),如果是element的data内容那么此text是element的唯一子节点,通过childNodes[0].data或firstChild.data获取element内容,如果是换行制表符那么此节点element的兄弟节点。
10.ProcessingInstruction
除node类之外,对于XML解析最重要的就是Document类和Element、text、Comment、Attr等类,前者配合parse()或parseString()将xml文件或字符串在内存中实例化为一个tree(document类型),后边的类用于对XML树做各种操作和查询。

鉴于几乎所有的可操作对象类都是继承于node类,这里贴一下node的各种属性和方法的链接:

另外再列出node一些常见的属性和方法:
Node.nodeType --详见上边对Node类的解释
Node.attributes --只有element类型的node才有此属性
Node.childNodes
--返回节点的子节点nodelist,与通过getElementsByTagName()获取nodelist的区别在于此方法只返回直接子节点而非全部子节点,此外这两个方法的最大区别是:childNodes返回的是所有子节点的集合,而getElementsByTagName(tagName)必须指定tagName。
Node.previousSibling --node的左兄弟节点,如果没有则返回none
Node.nextSibling --node的右兄弟节点,如果没有则返回none
Node.nodeName --不常用,因为继承于node的各种类都有自己的更便于识别的name属性,例如element.tagName
Node.appendChild(newChild)
另:如果要熟练的使用minidom API,那么请务必将https://docs.python.org/2/library/xml.dom.html 熟读,以上列出的各种继承于node的类都有一些自己独特的属性和方法,除了熟悉node类之外,熟悉这些继承子类的方法也是很有必要的。

XML文件解析示例:

--有一个如下的XML文件:proxool.xml:
<?xml version="1.0" encoding="utf-8"?>
<something-else-entirely>
<proxool>
<alias>myPool</alias>
<!-- mysql 连接配置,注意修改database_hostname为相应的数据库主机名、或IP地址 -->
<driver-url>
jdbc:mysql://dbsrv:3306/TEST?useUnicode=true&characterEncoding=UTF8
</driver-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<!-- 用户名、密码 -->
<driver-properties>
<property name="user" value="leo" />
<property name="password" value="leo" />
</driver-properties>
<!--自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 -->
<house-keeping-sleep-time>30000</house-keeping-sleep-time>
<house-keeping-test-sql>select CURRENT_DATE from dual
</house-keeping-test-sql>
<!--最大连接数(默认5个),超过了这个连接数,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定 -->
<maximum-connection-count>120</maximum-connection-count>
<!--最小连接数(默认2个) -->
<minimum-connection-count>5</minimum-connection-count>
<!--没有空闲连接可以分配而在队列中等候的最大请求数,超过这个请求数的用户连接就不会被接受,该参数已经不建议使用,由simultaneous-build-throttle替代 -->
<!--一个活动连接最大活动时间默认5分钟 -->
<maximum-active-time>3600000</maximum-active-time>
<!--最少保持的空闲连接数(默认2个),如果当前的连接池中的可用连接少于这个数值, 新的连接将被建立 -->
<prototype-count>5</prototype-count>
<!--可一次建立的最大连接数 -->
<simultaneous-build-throttle>20</simultaneous-build-throttle>
<!--如果为true,那么每个被执行的SQL语句将会在执行期被log记录 -->
<trace>false</trace>
</proxool>
</something-else-entirely>

现在将其中的内容解析为如下格式:

*****
描述:最大连接数(默认5个),超过了这个连接数,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定
配置项:maximum-connection-count
配置值:120
*****
描述:xxx
配置项:xxx
配置值:xxx
*****
......

代码如下:

# -*- coding:utf-8 -*-
# 本脚本适用于Python2和3
from xml.dom.minidom import parse
import xml.dom.minidom
import sys
# file = sys.argv[1]
file = "/root/proxool.xml"
# 先写一个判断节点是否包含element类型子节点的判断函数
def has_element_child(nodename):
has_element_child = 0
for child in nodename.childNodes:
if child.nodeType==1:
has_element_child += 1
return has_element_child
# 定义解析示例XML文件的方法
def parse_xml(file):
if not file:
sys.exit(0)
tree = parse(file) # document类型的解析树
root = tree.getElementsByTagName('proxool')[0] # 将父节点定位到proxool element
for child in root.childNodes:
if child.nodeType==child.ELEMENT_NODE and has_element_child(child)==0: # 当node为element类型,且无element类型的子节点时
print u'配置项'+": %s" % child.tagName
print u'配置值'+": %s" % child.firstChild.data.strip()
elif child.nodeType==child.ELEMENT_NODE and has_element_child(child)>0: # 当节点包含element类型子节点时
for child_child in child.childNodes:
if child_child.nodeType==child.ELEMENT_NODE:
print u'配置项'+": %s" % child_child.getAttribute('name')
print u'配置值'+": %s" % child_child.getAttribute('value')
elif child.nodeType==child.COMMENT_NODE: # 当node为comment类型时
print "*****"
print u'描述'+": %s" % child.data
else:
pass
# 处理示例XML文件
parse_xml(file)

XML文件比较修改示例:

minidom相比于DOM API最大的差别就是添加了node.writexml()、node.toprettyxml()等方法,这两个方法可以将你对XML解析树作出的修改写入文件中,现在我们将proxool.xml copy到proxool.xml.new中,并在proxool节点下添加一个子节点<new_tag name="Leo">For_Test</new_tag>,我们要比较新XML文件中比旧XML文件新增的配置项,对旧XML的配置项不做修改,代码如下:

# -*- coding:utf-8 -*-
# 本脚本适用于Python2和3
from xml.dom.minidom import parse
import xml.dom.minidom
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
old_file = sys.argv[1]
new_file = sys.argv[2]
# 先写一个判断节点是否包含element类型子节点的判断函数
def has_element_child(nodename):
has_element_child = 0
for child in nodename.childNodes:
if child.nodeType==1:
has_element_child += 1
return has_element_child
# 定义解析示例XML文件的方法
def match_xml(old_file,new_file):
if not new_file:
sys.exit(0)
tree_old = parse(old_file) # document类型的解析树
tree_new = parse(new_file)
root_old = tree_old.getElementsByTagName('proxool')[0] # 将父节点定位到proxool
root_new = tree_new.getElementsByTagName('proxool')[0]
old_dict = {} # 定义旧XML文件的tag和data的字典
new_dict = {}
for child in root_old.childNodes: #将tagName和data存入old_dict{}中
if child.nodeType==child.ELEMENT_NODE and has_element_child(child)==0: # 当node为element类型,且无element类型的子节点时
old_dict[child.tagName] = child.firstChild.data.replace("\n", "").replace("\t", "")
for child in root_new.childNodes:
if child.nodeType==child.ELEMENT_NODE and has_element_child(child)==0:
new_dict[child.tagName] = child.firstChild.data.replace("\n", "").replace("\t", "")
for tag,data in new_dict.items():
if not old_dict.get(tag): # 当旧XML中找不到对应的tag时,进行tag新增操作
new_element=tree_new.getElementsByTagName(tag)
for child in new_element:
root_old.appendChild(child) # 新增element节点
with open('proxool_modified.xml','w') as f:
tree_old.writexml(f)
f.close
# 处理示例XML文件
match_xml(old_file,new_file)
--比较XML文件:
# python xml_match_dom.py proxool.xml proxool.xml.new
--然后就可以在proxool_modified.xml中看到新的XML内容了

Python XML解析之DOM的更多相关文章

  1. Python XML解析之ElementTree

    参考网址: http://www.runoob.com/python/python-xml.html https://docs.python.org/2/library/xml.etree.eleme ...

  2. Python XML解析(转载)

    Python XML解析 什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). 你可以通过本站学习XML教程 XML 被设计用来传输和存储数据. XML是 ...

  3. python大法好——Python XML解析

    Python XML解析 什么是XML? XML 被设计用来传输和存储数据. XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识. 它也是元标记语言,即定义了用于定义其他与 ...

  4. - XML 解析 总结 DOM SAX PULL MD

    目录 目录 XML 解析 总结 DOM SAX PULL MD 几种解析方式简介 要解析的内容 DOM 解析 代码 输出 SAX 解析 代码 输出 JDOM 解析 代码 输出 DOM4J 解析 代码 ...

  5. Python XML解析

    什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). 你可以通过本站学习XML教程 XML 被设计用来传输和存储数据. XML是一套定义语义标记的规则,这 ...

  6. Python XML 解析

    什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据. XML 是一套定义语义标记的规则,这些标记将文档分成许多部件并 ...

  7. Python XML 解析Ⅱ

    make_parser方法 以下方法创建一个新的解析器对象并返回. 参数说明: parser_list - 可选参数,解析器列表 parser方法 以下方法创建一个 SAX 解析器并解析xml文档: ...

  8. XML解析之DOM详解及与SAX解析方法的比较

    XML解析(DOM) XML文件解析方法介绍 我们所用到的NSXMLParser是采用SAX方法解析 SAX(Simple API for XML) 只能读,不能修改,只能顺序访问,适合解析大型XML ...

  9. 【Java】XML解析之DOM

    DOM介绍 DOM(Document Object Model)解析是官方提供的XML解析方式之一,使用时无需引入第三方包,代码编写简单,方便修改树结构,但是由于DOM解析时是将整个XML文件加载到内 ...

随机推荐

  1. [Reversing.kr] Easy Crack Writeup

    题目:http://reversing.kr/ Easy Crack IDA打开.分析可知Sub_401080是关键函数.F5后. 当满足 则跳转成功.拼接后得到flag flag: Ea5yR3ve ...

  2. js获取input上传文件名和后缀

    var file = $("#filedata").val(); var pos = file.lastIndexOf("\\");  var filename ...

  3. C++ 动态生成对象

    1.啰嗦一下 说起C++,很多人都觉着难学,其实我也是这么觉着的,在这个移动端火到爆的时代,我都想改行了,移动端做东西那都是现有的第三方库,拿来就可以用,而且稳定性好,开发速度快,而且最关键的是出东西 ...

  4. C++ 断言

    assert宏 (基本概念与用法整理) assert宏的深入学习 1.运行时断言 1.1.assert属于运行时断言,可以在运行时判断给定条件是否为真,如果为真则什么也不做,否则打印一跳错误信息,然后 ...

  5. Java 多线程(一)—— 概念的引入

      并发和并行 并行:指两个或多个时间在同一时刻发生(同时发生): 并发:指两个或多个事件在一个时间段内发生. 在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 C ...

  6. TCP连接有效性检测方法

    在写TCP服务的时候经常需要面对的问题就是如何知道一个TCP连接当前是否有效,但这个问题对很多初入门的同学来说是很困惑的,主要原因是当对方关闭连接后,另一方无法有效的知道:对于同步操作来说可以通过设置 ...

  7. Linux~yum命令安装程序

    当我们使用linux的最小安装时,很多系统程序都没有被安装,这时,我们可以通过yum命令安装指定的包包,当然前提是你的linux处于联网状态的,下面说一下yum的用法 1 显示程序列表(联网的) yu ...

  8. Oracle学习笔记四

    一.PL/SQL编程 游标(光标Cursor) 为什么使用游标 在写java程序中有集合的概念,那么在pl/sq中也会用到多条记录,这时候我们就要用到游标,游标可以存储查询返回的多条数据. 语法: C ...

  9. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(9)- 从Parallel NOR启动

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的Parallel NOR启动. 上一篇讲i.MXRT从Raw NAND启动的文章 从Raw NAND启 ...

  10. spring学习(五) ———— 整合web项目(SSM)

    一.SSM框架整合 1.1.整合思路 从底层整合起,也就是先整合mybatis与spring,然后在编写springmvc. 1.2.开发需求 查询商品列表(从数据库中查询) 1.3.创建web工程 ...