XML DOM 节点树
XML DOM 把 XML 文档视为一种树结构。这种树结构被称为节点树。
可通过这棵树访问所有节点。可以修改或删除它们的内容,也可以创建新的元素。
这颗节点树展示了节点的集合,以及它们之间的联系。这棵树从根节点开始,然后在树的最低层级向文本节点长出枝条:
<!-- Copyright w3school.com.cn -->
<!-- W3School.com.cn bookstore example -->
<bookstore>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
</bookstore>
父、子和同级节点
节点树中的节点彼此之间都有等级关系。
父、子和同级节点用于描述这种关系。父节点拥有子节点,位于相同层级上的子节点称为同级节点(兄弟或姐妹)。
- 在节点树中,顶端的节点成为根节点
- 根节点之外的每个节点都有一个父节点
- 节点可以有任何数量的子节点
- 叶子是没有子节点的节点
- 同级节点是拥有相同父节点的节点
下面的图片展示出节点树的一个部分,以及节点间的关系:
第一个子节点 - 最后一个子节点
请看下面的 XML 片段:
<bookstore>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
在上面的 XML 中,<title>
元素是<book>
元素的第一个子节点,而<price>
元素是<book>
元素的最后一个子节点。
此外,<book>
元素是<title>
、<author>
、<year>
以及<price>
元素的父节点。
Python编程
-
导入DOM库,使用parse解析器打开xml文档,并将其解析为DOM文档,也就是内存中的一棵树,并得到这个对象
import xml.dom.minidom dom = xml.dom.minidom.parse("aligned_by_kyle_1.0.osm") # 拿到DOM的根 root = dom.documentElement
-
获取带有指定标签名称的所有元素
getElementsByTagName(name)
获取xml文档中的某个父节点下具有相同节点名的节点对象的集合。返回的是list
代码示例:bb = root.getElementsByTagName('node') print type(bb) print bb[0] b = bb[0] print b.nodeName print b.nodeValue
-
判断是否包含属性值hasAttribute(name)
from xml.dom.minidom import parse #minidom解析器打开xml文档并将其解析为内存中的一棵树 DOMTree=parse(r'book.xml') #获取xml文档对象,就是拿到树的根 booklist=DOMTree.documentElement print('DOM树的根对象:',booklist) if booklist.hasAttribute('type'): #判断根节点booklist是否有type属性 print('booklist 元素存在type属性') else: print('booklist 元素不存在type属性!!!') if booklist.getElementsByTagName('book')[0].hasAttribute('category'): #判断第一个book节点是否有category属性 print('第一个book节点存在category属性') else: print('第一个book节点不存在category属性!!!')
-
根据名字获取节点属性值getAttribute(name)
#coding: utf-8 import xml.dom.minidom dom = xml.dom.minidom.parse("aligned_by_kyle_1.0.osm") root = dom.documentElement itemlist = root.getElementsByTagName('node') item = itemlist[0] print item.getAttribute("id") print item.getAttribute("lat") print item.getAttribute("lon")
-
node.childNodes:返回节点node下所有的子节点组成的list
from xml.dom.minidom import parse #minidom解析器打开xml文档并将其解析为内存中的一棵树 DOMTree=parse(r'book.xml') #获取xml文档对象,就是拿到树的根 booklist=DOMTree.documentElement #获取booklist对象中所有book节点的list集合 books=booklist.getElementsByTagName('book') print('第一个book元素的所有子节点:',books[0].childNodes)
-
获取标签属性
#coding: utf-8 import xml.dom.minidom dom = xml.dom.minidom.parse("aligned_by_kyle_1.0.osm") #打开xml文档 root = dom.documentElement #得到xml文档对象 print "nodeName:", root.nodeName #每一个结点都有它的nodeName,nodeValue,nodeType属性 print "nodeValue:", root.nodeValue #nodeValue是结点的值,只对文本结点有效 print "nodeType:", root.nodeType print "ELEMENT_NODE:", root.ELEMENT_NODE
-
node.hasChildNodes():判断是否有子节点
from xml.dom.minidom import parse #minidom解析器打开xml文档并将其解析为内存中的一棵树 DOMTree=parse(r'book.xml') #获取xml文档对象,就是拿到树的根 booklist=DOMTree.documentElement if booklist.hasAttribute('type'): #判断根节点booklist是否有type属性,有则获取并打印属性值 print('Root element is ',booklist.getAttribute('type')) #获取booklist对象中所有的book节点的list集合 books=booklist.getElementsByTagName('book') print('book节点的个数为:',books.length) print () if books[0].hasChildNodes(): print('存在子节点:',books[0].childNodes) else: print('不存在子节点')
-
获取节点的文本值
from xml.dom.minidom import parse #minidom解析器打开xml文档并将其解析为内存中的一棵树 DOMTree=parse(r'book.xml') #获取xml文档对象,就是拿到树的根 booklist=DOMTree.documentElement if booklist.hasAttribute('type'): #判断根节点booklist是否有type属性,有则获取并打印属性值 print('Root element is ',booklist.getAttribute('type')) #获取booklist对象中所有的book节点的list集合 books=booklist.getElementsByTagName('book') print('book节点的个数为:',len(books)) print('book节点的个数为:',books.length) print () for book in books: print ("*******************book*******************") if book.hasAttribute('category'): print ('category is ',book.getAttribute('category')) #根据节点名title/author/pageNumber得到这些节点的集合list title=book.getElementsByTagName('title')[0] author=book.getElementsByTagName('author')[0] pageNumber=book.getElementsByTagName('pageNumber')[0] print ('title is ',title.childNodes[0].data) print ('author is ',author.childNodes[0].data) print ('pageNumber is ',pageNumber.childNodes[0].data)
-
修改节点属性的值
x = node.getAttributeNode("lat") x.nodeValue = str(1000.99)
-
创建/修改XML文件的demo
# -*- coding: utf-8 -*- import xml.dom.minidom as minidom doc = minidom.Document() # 创建根节点 a = minidom.getDOMImplementation() data = doc.createElement('data') # 在doc中创建一个data标签 doc.appendChild(data) # 将data标签添加到doc中 data_msg = doc.createTextNode('我是data') # 在doc中创建一个text文本 data.appendChild(data_msg) # 将text添加到data中 data.setAttribute('code', '0') # 给data标签添加/修改属性(属性名,属性值) data.setAttribute('name', 'query_zfy_info') # 给data标签添加/修改属性(属性名,属性值) message = doc.createElement('message') # 在doc中创建一个message标签 data.appendChild(message) # 将message标签添加到父标签data中 message_data = doc.createTextNode('请求失败') # 在doc中创建一个text文本 message.appendChild(message_data) # 将text文本添加到message_data标签中 message.setAttribute('a', '2') # 给message标签添加/修改属性(属性名,属性值) person1 = doc.createElement('老王') # 在doc中创建一个person1标签 message.appendChild(person1) # 将person1标签添加到父标签message中 person1_info = doc.createTextNode('生平事迹') # 在doc中创建一个person1_info文本 person1.appendChild(person1_info) # 将person1_info文本添加到person1中 person1.setAttribute('b','1') # 设置person1的属性 # 1.创建根节点 2.创建节点 3.给这个节点添加文本 4.设置属性 5.给这个节点添加父节点 # 将DOM对象写入文件 xml_path = './03.xml' f = open(xml_path, 'w') doc.writexml(writer=f, indent='\t', newl='\n', addindent='\t', encoding='utf-8') f.close() # 1、writer是文件对象 # 2、indent是每个tag前填充的字符,如:’ ‘,则表示每个tag前有两个空格 # 3、addindent是每个子结点的缩近字符 # 4、newl是每个tag后填充的字符,如:’\n’,则表示每个tag后面有一个回车 # 5、encoding是生成的XML信息头中的encoding属性值,在输出时minidom并不真正进行编码的处理,如果你保存的文本内容中有汉字,则需要自已进行编码转换。
<?xml version="1.0" encoding="utf-8"?> <data code="0" name="query_zfy_info"> 我是data <message a="2"> 请求失败 <老王 b="1">生平事迹</老王> </message> </data>
-
尽量使用
with...as
写入文件如果不用with语句,代码如下:
file = open("/tmp/foo.txt") data = file.read() file.close()
考虑到可能会保存异常
file = open("/tmp/foo.txt") try: data = file.read() finally: file.close()
虽然这段代码运行良好,但是太冗长了。这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。下面是with版本的代码:
with open("/tmp/foo.txt") as file: data = file.read()
具体到python+DOM写入文件:
# 保存修改到xml文件中 with open("./WriteTest.xml", 'w') as fh: # 4.writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式, # 第四个参数制定了换行格式,第五个参数制定了xml内容的编码。 doc.writexml(fh) print('恭喜,写入成功!')