天天看点

[Python学习]使用minidom来处理XML的示例 (二)–XML的写入

下面我来演示一下如何从无到有生成象catalog.xml一样的XML文件。

一、生成dom对象

>>> import xml.dom.minidom

>>> impl = xml.dom.minidom.getDOMImplementation()

>>> dom = impl.createDocument(None, ‘catalog’, None)

这样就生成了一个空的dom对象。其中catalog为文档元素名,即根元素名。

二、显示生成的XML内容

每一个dom结点对象(包括dom对象本身)都有输出XML内容的方法,如:toxml(), toprettyxml()

toxml()输出紧凑格式的XML文本,如:

<catalog><item>test</item><item>test</item></catalog>

toprettyxml()输出美化后的XML文本,如:

<catalog>

    <item>

        test

    </item>

    <item>

        test

    </item>

</catalog>

可以看出,它是将每个结点后面都加入了回车符,并且自动处理缩近。但对于每一个元素,如果元素只有文本内容,则我希望元素的tag与文本是在一起 的,如:

<item>test</item>

而不想是分开的格式,但minidom本身是不支持这样的处理。关于如何实现形如:

<catalog>

    <item>test</item>

    <item>test</item>

</catalog>

这样的XML格式,后面我们再说。

三、生成各种结点对象

dom对象拥有各种生成结点的方法,下面列出文本结点,CDATA结点和元素结点的生成过程。

1. 文本结点的生成

>>> text=dom.createTextNode(’test’)

test

要注意的是,在生成结点时,minidom并不对文本字符进行检查,象文本中如果出现了’<’,'&’之类的字符,应该转换为相应的 实体符号’&lt;’,'&amp;’才可以,这里没有做这个处理。

2. CDATA结点的生成

>>> data = dom.createCDATASection(’aaaaaa/nbbbbbb’)

>>> data.toxml()

‘<![CDATA[aaaaaa/nbbbbbb]]>’

CDATA是用于包括大块文本,同时可以不用转换’<’,'&’字符的标记,它是用<![CDATA[文本]]>来包括 的。但文本中不可以有”]]>”这样的串存在。生成结点时minidom不作这些检查,只有当你输出时才有可能发现有错。

3. 元素结点的生成

>>> item = dom.createElement(’caption’)

>>> item.toxml()

‘<caption/>’

对于象元素这样的结点,生成的元素结点其实是一个空元素,即不包含任何文本,如果要包含文本或其它的元素,我们需要使用appendChild() 或insertBefore()之类的方法将子结点加就到元素结点中。如将上面生成的text结点加入到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>’

四、生成dom对象树

我们有了dom对象,又知道了如何生成各种结点,包括叶子结点(不包含其它结点的结点,如文本结点)和非叶子结点(包含其它结点的结点,如元素结 点)的生成,然后就需要利用结点对象本身的appendChild()或insertBefore()方法将各个结点根据在树中的位置连起来,串成一棵 树。最后要串到文档结点上,即根结点上。如一个完整的示例为:

>>> import xml.dom.minidom

>>> impl = xml.dom.minidom.getDOMImplementation()

>>> dom = impl.createDocument(None, ‘catalog’, None)

>>> root = dom.documentElement

>>> item = dom.createElement(’item’)

>>> text = dom.createTextNode(’test’)

>>> item.appendChild(text)

<DOM Text node “test”>

>>> root.appendChild(item)

<DOM Element: item at 0xb9cf80>

>>> print root.toxml()

<catalog><item>test</item></catalog>

五、简单生成元素结点的函数

下面是我写的一个小函数,用于简单的生成类似于:

<caption>test</caption>

或形如:

<item><![CDATA[test]]></item>

的元素结点

1       def makeEasyTag(dom, tagname, value, type=’text’):

2           tag = dom.createElement(tagname)

3           if value.find(’]]>’) > -1:

4               type = ‘text’

5           if type == ‘text’:

6               value = value.replace(’&’, ‘&amp;’)

7               value = value.replace(’<’, ‘&lt;’)

8               text = dom.createTextNode(value)

9           elif type == ‘cdata’:

10              text = dom.createCDATASection(value)

11          tag.appendChild(text)

12          return tag

参数说明:

  • dom为dom对象
  • tagname为要生成元素的名字,如’item’
  • value为其文本内容,可以为多行
  • type为文本结点的格式,’text’为一般Text结点,’cdata’为CDATA结点

函数处理说明:

  • 首先创建元素结点
  • 查找文本内容是否有’]]>’,如果找到,则此文本结点只可以是Text结点
  • 如果结点类型为’text’,则对文本内容中的’<’替换为’&lt;’,’&’替换为’&amp;’,再生成文 本结点
  • 如果结点类型为’cdata’,则生成CDATA结点
  • 将生成的文本结点追加到元素结点上

因此这个小函数可以自动地处理字符转化及避免CDATA结点中出现’]]>’串。

上面生成’item’结点的语句可以改为:

>>> item = makeEasyTag(dom, ‘item’, ‘test’)

>>> item.toxml()

‘<item>test</item>’

六、写入到XML文件中

dom对象树已经生成好了,我们可以调用dom的writexml()方法来将内容写入文件中。writexml()方法语法格式为:

writexml(writer, indent, addindent, newl, encoding)
  • writer是文件对象
  • indent是每个tag前填充的字符,如:’  ‘,则表示每个tag前有两个空格
  • addindent是每个子结点的缩近字符
  • newl是每个tag后填充的字符,如:’/n’,则表示每个tag后面有一个回车
  • encoding是生成的XML信息头中的encoding属性值,在输出时minidom并不真正进行编码的处理,如果你保存的文本内容中有汉 字,则需要自已进行编码转换。

writexml方法是除了writer参数必须要有外,其余可以省略。下面给出一个文本内容有汉字的示例:

1       >>> import xml.dom.minidom

2       >>> impl = xml.dom.minidom.getDOMImplementation()

3       >>> dom = impl.createDocument(None, ‘catalog’, None)

4       >>> root = dom.documentElement

5       >>> text = unicode(’汉字示例’, ‘cp936′)

6       >>> item = makeEasyTag(dom, ‘item’, text)

7       >>> root.appendChild(item)

8       <DOM Element: item at 0xb9ceb8>

9       >>> root.toxml()

10      u’<catalog><item>/u6c49/u5b57/u793a/u4f8b</item></catalog>’

11      >>> f=file(’d:/test.xml’, ‘w’)

12      >>> import codecs

13      >>> writer = codecs.lookup(’utf-8′)[3](f)

14      >>> dom.writexml(writer, encoding=’utf-8′)

15      >>> writer.close()

5行 因为XML处理时内部使用Unicode编码,因此象汉字首先要转成Unicode,如果你不做这一步minicode并不检查,并且保存时可能不会出 错。但读取时可能会出错。

12-13行 生成UTF-8编码的写入流对象,这样在保存时会自动将Unicode转换成UTF-8编码。

这样写XML文件就完成了。