python 解析xml:DOM与 python 库xml.dom.minidom

转自:http://blog.chinaunix.net/uid-22183602-id-3035397.html

转载来源:http://blog.csdn.net/tpfly/article/details/3948029

  DOM把xml每个元素、属性、文本等信息储存在称为节点的数据类型中,xml.dom中Node(节点)是xml文档中每一个component
的父类。XML 中最常见的节点类型包括:
*元素:元素是 XML 的基本构造模块。通常,元素拥有子元素、文本节点,或两者的组合。元素节点也是能够拥有属性的唯一节点类型。
*属性:属性节点包含关于元素节点的信息,但是并不实际认为是元素的孩子,比如在下面的例子中:
*文本:文本节点就是名副其实的文本。它可以由更多信息组成,也可以只包含空白。
*文档:文档节点是文档中其他所有节点的父亲。
其他节点类型不太常用,但是在某些场合下仍然是必需的。它们包括:
*CDATA: 字符数据(Character Data)的缩写,这是一个特殊的节点,它包含不应该被解析器分析的信息。相反,它包含的信息应该以纯文本传递。例如,可能会为了特殊目的而存储 HTML 标签。在通常情形下,处理器可能尝试为所存储的每个标签创建元素,而这样可能导致文档不是格式良好
的。这些问题可用通过使用 CDATA 节(section)来避免。这些节使用特殊的符号来编写:
<[CDATA[<b>
      Important:  Please keep head and hands inside ride at <i>all
times</i>.
      </b>]]>
*注释:注释包括关于数据的信息,通常被应用程序忽略。它们写为如下形式:
<!--  This is a comment. -->
*处理指令:处理指令是专门针对应用程序的信息。其中一些例子包括要执行的代码或者关于从何处寻找样式表的信息。例如:
<?xml-stylesheet type="text/xsl" href="foo.xsl"?>
python xml.dom中节点类型由节点中nodeType属性得到,该属性取如下值:ELEMENT_NODE,
ATTRIBUTE_NODE, TEXT_NODE, CDATA_SECTION_NODE, ENTITY_NODE,
PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_NODE,
DOCUMENT_TYPE_NODE, NOTATION_NODE

示例:把上面的xml例子保存为test-utf8.xml,一定用utf8的编码保存。然后在python提示符下输入:
>>> from xml.dom import minidom
>>> xmldoc=minidom.parse('test-utf8.xml')

得到一个Document类型变量xmldoc, 它是一个保存文档所有信息的树结构。用Node的toxml()函数可以得到节点中保存的xml字符串。因为Document是Node的子类,所以可以应用toxml函数:
>>> print xmldoc.toxml()

<?xml version="1.0" ?><rss version="2.0">
        <channel>
                <title>pilgrim</title>
                <link>http://blog.xxx.com</link>
                <description>博客描述</description>
                <generator>Terac Miracle 3.8</generator>
                <item>
                        <title>文章标题</title>
                        <link>http://blog.xxx.com/e_42678.html</link>
                        <description>文章内容</description>
                        <pubDate>Sun, 23 Sep 2007 23:32:00 +0800</pubDate>
                </item>
                <item>
                        <title>文章标题</title>
                        <link>http://blog.xxx.com/e_39749.html</link>
                        <description>文章内容</description>
                        <pubDate>Mon, 27 Aug 2007 23:58:00 +0800</pubDate>
                </item>
        </channel>
</rss>
要得到文档的根节点,用Document的documentElement属性:
>>> root=xmldoc.documentElement
>>> root

<DOM Element: rss at 0x14f29e0>
>>> print root.toxml()

<rss version="2.0">
        <channel>
                <title>pilgrim</title>
                <link>http://blog.xxx.com</link>
                <description>博客描述</description>
                <generator>Terac Miracle 3.8</generator>
                <item>
                        <title>文章标题</title>
                        <link>http://blog.xxx.com/e_42678.html</link>
                        <description>文章内容</description>
                        <pubDate>Sun, 23 Sep 2007 23:32:00 +0800</pubDate>
                </item>
                <item>
                        <title>文章标题</title>
                        <link>http://blog.xxx.com/e_39749.html</link>
                        <description>文章内容</description>
                        <pubDate>Mon, 27 Aug 2007 23:58:00 +0800</pubDate>
                </item>
        </channel>
</rss>
root有一个子元素channel,这些子元素由root的childNodes保存,其中第一个子节点由root.firstChild引用,最后一个子节点由root.lastChild引用:

>>> print root.firstChild.toxml()
>>> print root.lastChild.toxml()
>>> print root.childNodes[1].toxml()

<channel>
                <title>pilgrim</title>
                <link>http://blog.xxx.com</link>
                <description>博客描述</description>
                <generator>Terac Miracle 3.8</generator>
                <item>
                        <title>文章标题</title>
                        <link>http://blog.xxx.com/e_42678.html</link>
                        <description>文章内容</description>
                        <pubDate>Sun, 23 Sep 2007 23:32:00 +0800</pubDate>
                </item>
                <item>
                        <title>文章标题</title>
                        <link>http://blog.xxx.com/e_39749.html</link>
                        <description>文章内容</description>
                        <pubDate>Mon, 27 Aug 2007 23:58:00 +0800</pubDate>
                </item>
        </channel>
因为firstChild和lastChild是由channel前后的空白和换行形成的文本型节点,所以会打印出空行。
访问xmldoc:
xml各部分与minidom关系对应:
<Node.tagName Node.attributes.keys() = Node.attributes['key'].value
attributes可以像dict一样使用,用keys()得到属性列表,用Node.attributes['key'].value得到属性值

        Node.childNodes保存个子节点,第一个节点Node.firstChild,最后一个Node.lastChild,可以像list一样使用。
        <Node.tagName>TextNode.data</Node.tagName>
</Node.tagName>
修改xmldoc:
添加节点:首先创建节点:Document.createElement(tagName)
Document.createTextNode(data)再把节点添加到Node下面:Node.appendChild()
node.insertBefore(new,ref)
删除节点Node.removeChild()
替换节点 Node.replaceChild(new,old)
添加删除属性 更改属性
Element.setAttribute(name,value) Element.removeAttribute(name) 也可以用
Element.attributes['key']=value来直接指定,value是unicode字符串。

4 例子
dir2xml.py是由目录结构生成xml文件的例子,xml2dir.py是根据生成的xml文件内容重建目录,当然建立出的文件都是没有内容的空文件。
文件dir2xml.py:

#!/usr/bin/env python
#-*-   coding:   gbk   -*-
"""遍历目录,根据目录结构生成xml文件。
dir2xml dirname xmlfilename
"""
import os
from xml.dom import minidom as pydom
import sys
def usage():
    print "usage:",sys.argv[0],"dirname xmlfilename"

def dir2xml(dirname):
    """遍历目录,根据目录内容生成xml Document对象
    dirname是路径名,必须是标准的路径名,前后没有空格,后面不带/或//。
"""
    impl=pydom.getDOMImplementation()
    newdoc=impl.createDocument(None,"dir",None)
    rootdir=newdoc.documentElement
    rootdir.attributes['name']=os.path.basename(dirname)

    def walkdir(dirname,node,document):   #对目录递归遍历,这里用os.path.walk更简单
        for file in os.listdir(dirname):
            if os.path.isfile(os.path.join(dirname,file)):
                newFileEl=document.createElement('file')
                newFileEl.attributes['name']=file.encode('utf8')
                node.appendChild(newFileEl)
            elif os.path.isdir(os.path.join(dirname,file)):
                newFileEl=document.createElement('dir')
                newFileEl.attributes['name']=file.encode('utf8')
                node.appendChild(newFileEl)
                walkdir(os.path.join(dirname,file),newFileEl,document)
    walkdir(dirname,rootdir,newdoc)
    return newdoc

if __name__ == '__main__':
    if len(sys.argv)<3:
        usage()
        sys.exit()
    if not os.path.isdir(sys.argv[1]):
        print 'Error:',sys.argv[1],'is not a directory.'
        sys.exit()
    xmlfile=file(sys.argv[2],'w')

newdoc=dir2xml(unicode(os.path.normpath(sys.argv[1].strip()),'gb2312'))
    newdoc.writexml(xmlfile,'/n','  ')
    xmlfile.close()

文件xml2dir.py:

#!/usr/bin/env python
# -*- coding: cp936 -*-
"""由xml文档生成目录
xml2dir xmlfilename dirname
"""
import os
from xml.dom import minidom as pydom
import sys

def usage():
    print "usage:",sys.argv[0],"dirname xmlfilename"

def xml2dir(xmlElement,dirname):
    """由xml文档生成目录
    xml2dir(xmlElement,dirname)
    xmlElement是xml文档元素,标签名file表示文件,dir表示目录。属性name表示文件或目录名
    dirname是保存xmlElement整个节点的目录名,将在dirname目录中开始建立xmlElement目录树。"""
    if not os.path.exists(dirname):
        os.mkdir(dirname)
    cwd=os.getcwd()
    os.chdir(dirname)
    for childNode in xmlElement.childNodes:
        if childNode.nodeType not in
(childNode.ELEMENT_NODE,childNode.DOCUMENT_NODE):
            continue
        if childNode.tagName == u'file':
            file(childNode.attributes['name'].value,'w').close()
        elif childNode.tagName == u'dir':
            if not os.path.exists(childNode.attributes['name'].value):
                os.mkdir(childNode.getAttribute('name'))
            xml2dir(childNode,childNode.getAttribute('name'))
    os.chdir(cwd)

if __name__ == '__main__':
    if len(sys.argv)<3:
        usage()
        sys.exit()
    try:
        xmlfile=file(sys.argv[1],'r')
    except:
        sys.stderr.write("XML file not found or cannot access.")
        sys.exit()
    xmldoc=pydom.parse(xmlfile)
    xml2dir(xmldoc,os.path.normpath(sys.argv[2].strip()))
    xmlfile.close()

posted on 2015-01-14 20:27  可可_小虾米  阅读(372)  评论(0编辑  收藏  举报

导航