使用minidom来处理XML的示例(Python 学习)(转载)
http://blog.youkuaiyun.com/ywchen2000/archive/2006/07/04/876742.aspx
http://blog.youkuaiyun.com/zhangj1012003_2007/archive/2010/04/23/5514807.aspx
http://blog.youkuaiyun.com/zhangj1012003_2007/archive/2010/04/22/5514929.aspx
http://blog.youkuaiyun.com/zhangj1012003_2007/archive/2010/04/22/5514935.aspx
一.XML的读取.
在 NewEdit 中有代码片段的功能,代码片段分为片段的分类和片段的内容。在缺省情况下都是用XML格式保存的。下面我讲述一下,如何使用minidom来读取和保存XML文件。
XML信息体是由树状元素组成。每个XML文档都有一个文档元素,也就是树的根元素,所有其它的元素和内容都包含在根元素中。
DOM是Document Object Model的简称,它是以对象树来表示一个XML文档的方法,使用它的好处就是你可以非常灵活的在对象中进行遍历。
>>> import xml.dom.minidom
>>> dom = xml.dom.minidom.parse('d:/catalog.xml')
这样我们得到了一个dom对象,它的第一个元素应该是catalog。
每一个结点都有它的nodeName,nodeValue,nodeType属性。nodeName为结点名字。
nodeValue是结点的值,只对文本结点有效。nodeType是结点的类型,现在有以下几种:
这些结点通过名字很好理解。catalog是ELEMENT_NODE类型。
访问子元素、子结点的方法很多,对于知道元素名字的子元素,可以使用getElementsByTagName方法,如读取maxid子元素:
>>> root.getElementsByTagName('maxid')
[<DOM Element: maxid at 0xb6d0a8>]
这样返回一个列表,由于我们的例子中maxid只有一项,因此列表也只有一项。
如果想得到某个元素下的所有子结点(包括元素),可以使用childNodes属性:
getElementsByTagName可以搜索当前元素的所有子元素,包括所有层次的子元素。childNodes只保存了当前元素的第一层子结点。
这样我们可以遍历childNodes来访问每一个结点,判断它的nodeType来得到不同的内容。如,打印出所有元素的名字:
对于文本结点,想得到它的文本内容可以使用: .data属性。
对于简单的元素,如:<caption>Python</caption>,我们可以编写这样一个函数来得到它的内容(这里为Python)。
如果一个元素有属性,那么可以使用getAttribute方法,如:
下面让我们简单地小结一下如何使用minidom来读取XML中的信息
二.写入.
下面我来演示一下如何从无到有生成象catalog.xml一样的XML文件。
这样就生成了一个空的dom对象。其中catalog为文档元素名,即根元素名。
每一个dom结点对象(包括dom对象本身)都有输出XML内容的方法,如:toxml(), toprettyxml()
可以看出,它是将每个结点后面都加入了回车符,并且自动处理缩近。但对于每一个元素,如果元素只有文本内容,则我希望元素的tag与文本是在一起的,如:
而不想是分开的格式,但minidom本身是不支持这样的处理。关于如何实现形如:
dom对象拥有各种生成结点的方法,下面列出文本结点,CDATA结点和元素结点的生成过程。
要注意的是,在生成结点时,minidom并不对文本字符进行检查,象文本中如果出现了'<','&'之类的字符,应该转换为相应的实体符号'<','&'才可以,这里没有做这个处理。
>>> data = dom.createCDATASection('aaaaaa\nbbbbbb')
>>> data.toxml()
'<![CDATA[aaaaaa\nbbbbbb]]>'
>>> item = dom.createElement('caption')
>>> item.toxml()
'<caption/>'
>>> item.appendChild(text)
<DOM Text node "test">
>>> item.toxml()
'<caption>test</caption>'
使用元素对象的setAttribute()方法可以向元素中加入属性,如:
>>> item.setAttribute('id', 'idvalue')
>>> item.toxml()
'<caption id="idvalue">test</caption>'
- 首先创建元素结点
- 查找文本内容是否有']]>',如果找到,则此文本结点只可以是Text结点
- 如果结点类型为'text',则对文本内容中的'<'替换为'<','&'替换为'&',再生成文本结点
- 如果结点类型为'cdata',则生成CDATA结点
- 将生成的文本结点追加到元素结点上
因此这个小函数可以自动地处理字符转化及避免CDATA结点中出现']]>'串。
>>> item = makeEasyTag(dom, 'item', 'test')
>>> item.toxml()
'<item>test</item>'
dom对象树已经生成好了,我们可以调用dom的writexml()方法来将内容写入文件中。writexml()方法语法格式为:
- writer是文件对象
- indent是每个tag前填充的字符,如:' ',则表示每个tag前有两个空格
- addindent是每个子结点的缩近字符
- newl是每个tag后填充的字符,如:'\n',则表示每个tag后面有一个回车
- encoding是生成的XML信息头中的encoding属性值,在输出时minidom并不真正进行编码的处理,如果你保存的文本内容中有汉字,则需要自已进行编码转换。
writexml方法是除了writer参数必须要有外,其余可以省略。下面给出一个文本内容有汉字的示例:
对于dom对象的writexml()方法,虽然可以控制一些格式上的输出,但结果并不让人满意。比如我想实现:
如果是象下面的输出结果我无法区分原来文本中是否带有空白,而上一种结果则不存在这一问题。好在我在wxPython自带的XML资源编辑器(xred)发现了美化的代码。代码如下:
Indent基本的想法就是递归遍历所有子结点,在所有需要加入回车和缩近的地方插入相应的文本结点。这样再使用writexml()输出时就是缩近好了的。具体程序不再细说,直接用就行了。
Indent()要修改原dom对象,因此在调用它之前最好先复制一个临时dom对象,使用完毕后再清除这个临时dom对象即可。下面是详细的调用过程:
1行 克隆一个dom对象
2行 进行缩近处理
3-4行 进行UTF-8编码处理
5行 生成XML文件
6行 清除dom对象的内容
example: 生成test3.xml
import xml.dom.minidom
impl = xml.dom.minidom.getDOMImplementation()
dom = impl.createDocument(None, 'manifest', None)
root = dom.documentElement
item = dom.createElement('item')
text = dom.createTextNode('test')
item.appendChild(text)
root.appendChild(item)
item.setAttribute('id', '101')
item.setAttribute('name', 'shanghai')
item1 = dom.createElement('item')
item1.setAttribute('id', '102')
item1.setAttribute('name', 'beijing')
root.appendChild(item1)
f=file('test3.xml', 'w')
dom.writexml(f,indent="", addindent = " ", newl= "\n",encoding='utf-8')
f.close()