Python XML解析之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()用于获取整个树唯一的根节点
概念解析:
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)
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文件比较修改示例:
# -*- 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的更多相关文章
- Python XML解析之ElementTree
参考网址: http://www.runoob.com/python/python-xml.html https://docs.python.org/2/library/xml.etree.eleme ...
- Python XML解析(转载)
Python XML解析 什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). 你可以通过本站学习XML教程 XML 被设计用来传输和存储数据. XML是 ...
- python大法好——Python XML解析
Python XML解析 什么是XML? XML 被设计用来传输和存储数据. XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识. 它也是元标记语言,即定义了用于定义其他与 ...
- - XML 解析 总结 DOM SAX PULL MD
目录 目录 XML 解析 总结 DOM SAX PULL MD 几种解析方式简介 要解析的内容 DOM 解析 代码 输出 SAX 解析 代码 输出 JDOM 解析 代码 输出 DOM4J 解析 代码 ...
- Python XML解析
什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). 你可以通过本站学习XML教程 XML 被设计用来传输和存储数据. XML是一套定义语义标记的规则,这 ...
- Python XML 解析
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据. XML 是一套定义语义标记的规则,这些标记将文档分成许多部件并 ...
- Python XML 解析Ⅱ
make_parser方法 以下方法创建一个新的解析器对象并返回. 参数说明: parser_list - 可选参数,解析器列表 parser方法 以下方法创建一个 SAX 解析器并解析xml文档: ...
- XML解析之DOM详解及与SAX解析方法的比较
XML解析(DOM) XML文件解析方法介绍 我们所用到的NSXMLParser是采用SAX方法解析 SAX(Simple API for XML) 只能读,不能修改,只能顺序访问,适合解析大型XML ...
- 【Java】XML解析之DOM
DOM介绍 DOM(Document Object Model)解析是官方提供的XML解析方式之一,使用时无需引入第三方包,代码编写简单,方便修改树结构,但是由于DOM解析时是将整个XML文件加载到内 ...
随机推荐
- [Swift]LeetCode1000. 合并石头的最低成本 | Minimum Cost to Merge Stones
There are N piles of stones arranged in a row. The i-th pile has stones[i] stones. A move consists ...
- SCOI2019 退役记
退役了.D2没有翻盘,愉快出队,文化课见. 19年4月14日:某校第一届的最后一名OIer退出竞赛. 留坑. 万一退役失败了呢
- Java 多线程(四)—— 单例模式
这篇博客介绍线程安全的应用——单例模式. 单例模式 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一 ...
- asp.net core 系列 7 Razor框架路由(上)
一.概述 在上二篇中,主要是介绍了asp.net core mvc中路由的使用,这篇继续介绍路由在ASP.NET Core Razor中的使用.Razor Pages应该使用默认的传统路由,从应用程序 ...
- Android--MP3播放器MediaPlayer
前言 Android提供了常见的音频.视频的编码.解码机制.借助于多媒体类MediaPlayer的支持,开发人员可以很方便在在应用中播放音频.视频.本篇博客主要讲解在Android平台下如何播放一个音 ...
- Chapter 4 Invitations——28
"Oh, thanks, now that's all cleared up." Heavy sarcasm. “哦,真感谢,现在一切都清楚了.” 我很讽刺的说道 I realiz ...
- ES6躬行记(5)——对象字面量的扩展
一.简洁属性和方法 当创建对象字面量时,如果属性值是与属性同名的已定义的标识符(例如变量.常量等),那么ES6允许省略冒号和属性值,这样就能避免冗余的初始化.下面分别用传统的键值对和最新的简写方式创建 ...
- [UOJ310] 黎明前的巧克力
Sol 某比赛搬了这题. 首先选择两个不交非空子集且异或和为0的方案数,等价于选择一个异或和为0的集合,并把它分成两部分的方案数. 这显然可以DP来算,设 \(f[i][j]\) 表示前\(i\)个数 ...
- Centos 7 Puppet之foreman介绍安装测试
一.简介 1.前言(引用一下网上的资料) 随着企业的 Linux 系统数量越来越多,管理问题便成为一个相对麻烦并需要急 迫解决的问题,这里有 2 个 Key Message:1)统一管控体系非常重要, ...
- 多线程Thread,线程池ThreadPool
首先我们先增加一个公用方法DoSomethingLong(string name),这个方法下面的举例中都有可能用到 #region Private Method /// <summary> ...