XML是派生于SGML(通用标记语言标准),相当于是给文本进行标记。将标签放在“<>”之中,便于解析。XML文档是层次结构的,例如如下XML文档:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!--Sample XML Document-test.xml-->
<book>
    <title>Sample XML Thing</title>
    <author>
        <name><first>Ben</first> <last>Smith</last></name>
        <affiliation>Spring</affiliation>
    </author>
    
    <chapter number="1">
        <title>First Chapter</title>
        <para>
            I think widgetsw are great.<company>Spring</company>
        </para>
    </chapter>
<book>

从中可以看到xml文档的层次结构性。

通常,当使用xml文档时,会使用一个预先定义号的XML解析库,这些库通常使用下面两种方法之一来展示xml文档:树和事件。一个基于事件的解析器可以扫描文档,并在有感兴趣的内容出现的时候进行通知。例如第7章的HTMLParser例子就是一个基于事件解析器的例子。对于基于事件的解析器,可以实现编写号当文档中出现感兴趣的事情的时候,程序该做什么。

另一方面,基于树的解析器会扫描全部的文档,通过产生嵌套的数据结构来展现文档。对于一个基于树的解析器,可以在得到解析的节后后,浏览一下并挑除需要的信息。另外一个基于树的解析器的有点是,可以在把数据存入内容后进行修改,并通过系统把修改后的xml文档写到磁盘上。

Python对这两种方法都有支持。它的SAX模块可以实现基于事件的解析,它的DOM模块可以实现基于树的解析。本章只介绍DOM模块。。

#!/usr/bin/env python
#-*-coding:utf-8-*-

from xml.dom import minidom, Node

def scanNode(node, level=0):
    msg=node.__class__.__name__
    if node.nodeType==Node.ELEMENT_NODE:
        msg+=", tag: "+node.tagName
    print " "*level*4, msg
    if node.hasChildNodes:
        for child in node.childNodes:
            scanNode(child, level+1)
    
doc=minidom.parse('test.xml')
scanNode(doc)

以上代码生成如下结果:

 Document
     Comment
     Element, tag: book
         Text
         Element, tag: title
             Text
         Text
         Element, tag: author
             Text
             Element, tag: name
                 Element, tag: first
                     Text
                 Text
                 Element, tag: last
                     Text
             Text
             Element, tag: affiliation
                 Text
             Text
         Text
         Element, tag: chapter
             Text
             Element, tag: title
                 Text
             Text
             Element, tag: para
                 Text
                 Element, tag: company
                     Text
                 Text
             Text
         Text

ELENMENT对象表示文档中成对出现的标签。TEXT表示实际的文本,即使在处理空白内容的时候也经常建立TEXT对象。。在源代码中,parse()函数载入和解析XML文档并返回顶端节点。从这个节点开始向下访问其他的节点,就是scanNode()所做的事。


除了可以用dom库来分析xml文档,产生对象树之外,还可以反着用:生成一个对象的树,并使用库函数来写出一个xml文档。还可以从一个存在的文档中得到树后,修改它并写出结果。

#!/usr/bin/env python

from xml.dom import minidom, Node

doc=minidom.Document()

doc.appendChild(doc.createComment("Sample XML Document"))

#Generate the book

book=doc.createElement('book')
doc.appendChild(book)

#The title

title=doc.createElement('title')
title.appendChild(doc.createTextNode('Sample XML Thing'))
book.appendChild(title)

#The author section

author=doc.createElement('author')
book.appendChild(author)
name=doc.createElement('name')
author.appendChild(name)
firstname=doc.createElement('first')
name.appendChild(firstname)
firstname.appendChild(doc.createTextNode('Ben'))
name.appendChild(doc.createTextNode(' '))
lastname=doc.createElement('last')
lastname.appendChild(doc.createTextNode('Smith'))
name.appendChild(lastname)

affiliation=doc.createElement('affiliation')
author.appendChild(affiliation)
affiliation.appendChild(doc.createTextNode('Spring'))

#The chapter

chapter=doc.createElement('chapter')
book.appendChild(chapter)
chapter.setAttribute('number', '1')
title=doc.createElement('title')
chapter.appendChild(title)
title.appendChild(doc.createTextNode('First Chapter'))

para=doc.createElement('para')
chapter.appendChild(para)
para.appendChild(doc.createTextNode('I think widgets are great.'))
company=doc.createElement('company')
para.appendChild(company)
company.appendChild(doc.createTextNode('Spring'))

para.appendChild(doc.createTextNode('.'))

print doc.toprettyxml(indent=' ')

生成如下内容:

<?xml version="1.0" ?>
<!--Sample XML Document-->
<book>
 <title>Sample XML Thing</title>
 <author>
  <name>
   <first>Ben</first>
    
   <last>Smith</last>
  </name>
  <affiliation>Spring</affiliation>
 </author>
 <chapter number="1">
  <title>First Chapter</title>
  <para>
   I think widgets are great.
   <company>Spring</company>
   .
  </para>
 </chapter>
</book>

如果在最后,用toxml()(不带参数)替换toprettyxml(),会看到所有的文档都放到了一行里面,这就为DOM树提供一个真实的表示方法(不含任何空格),不过对人来说不美观。


XML-RPC

XML-RPC是一种与任何语言都没有关系,可以在网络上传递请求和应答的方法。它使用XML来作为基本的数据表示,但是XML-RPC用户不需要真正了解XML。

书中使用的例子与O'Reilly的市场服务有关,这个服务在2006年就关闭了,因此无法测试。。。。