home changes contents help options

078:XMLを解析する

以下の XML を解析対象としてみます。この XML は builtin.xml というファイルに収まっているものとします。

<?xml version="1.0" encoding="utf-8" ?>
<built-in>
  <type>
    <name>int</name>
    <class>numeric</class>
  </type>
  <type>
    <name>float</name>
    <class>numeric</class>
  </type>
  <type>
    <name>str</name>
    <class>sequence</class>
  </type>
  <type>
    <name>list</name>
    <class>sequence</class>
  </type>
  <type>
    <name>tuple</name>
    <class>sequence</class>
  </type>
  <type>
    <name>dict</name>
    <class>mapping</class>
  </type>
</built-in>

これから紹介するコードは各モジュールを用いて builtin.xml から次の出力を得るものです。

int
float
str
list
tuple
dict

ElementTree?

Python で XML を読む方法は多数あるのですが、まずは ElementTree? を紹介します。 Python 2.5 より標準入りした使いやすいモジュールです。 XML を Python オブジェクトのツリーとし、直感的に扱えるようにしてくれます。

import xml.etree.ElementTree as ET
tree = ET.parse('builtin.xml')
for element in tree.getroot():
    print element.find('name').text

SAX

Python には SAX の実装 sax が用意されています。SAX はイベント駆動型の標準 API です。

import sys
import xml.sax
from xml.sax.handler import ContentHandler

class printNameHandler(ContentHandler):
    def __init__(self, writer=sys.stdout):
        self._writer = writer
        self._node = []
        ContentHandler.__init__(self)

    def startElement(self, name, attrs):
        self._node.append(name)

    def endElement(self, name):
        self._node.pop()

    _name_node = [u'built-in', u'type', u'name']
    def characters(self, data):
        if self._node == self._name_node:
            self._writer.write(u'%s\n' % data)

parser = xml.sax.make_parser()
parser.setContentHandler(printNameHandler())
parser.parse(u'builtin.xml')

DOM

Python には DOM の簡易実装 minidom が用意されています。DOM は W3C 勧告の標準 API で、文章データをツリー構造として扱います。 minidom とは DOM 1.0 にいくつかの DOM 2 の機能を追加したものです。

import xml.dom.minidom

dom = xml.dom.minidom.parse(u'builtin.xml')
for name in dom.getElementsByTagName(u'name'):
    print name.firstChild.data

Expat

Python には C言語で書かれたストリーム志向パーサー Expat およびそのラッパーが用意されています。

import xml.parsers.expat

_node = []
_name_node = [u'built-in', u'type', u'name']

def start_element(name, attrs):
    _node.append(name)

def end_element(name):
    _node.pop()

def character_data(data):
    if _node == _name_node:
        print data

parser = xml.parsers.expat.ParserCreate()
parser.StartElementHandler = start_element
parser.EndElementHandler = end_element
parser.CharacterDataHandler = character_data

xml = open(u'builtin.xml')
try:
    parser.ParseFile(xml)
finally:
    xml.close()

BeautifulSoup?

サードパーティ製モジュールにも便利なものがあります。そのうちの1つ、 BeautifulSoup? を紹介します。 BeautifulSoup?ElementTree? のように XML を Python で扱いやすいオブジェクトのツリーに変換してくれます。

from BeautifulSoup import BeautifulStoneSoup

soup = BeautifulStoneSoup(open(u'builtin.xml', 'rb').read())
for name in soup.findAll('name'):
    print name.string

より高度、実験的なモジュールたち

ここまでは XML を手軽に扱う方向で作成されたモジュールでしたが、より高度な機能を必要とする場合もあるかと思います。次のものが役に立つでしょう。

PyXML?
XML-SIG の PyXML? は DOM の完全な実装を提供しています。
4Suite
4Suite はXPATH, XSLT, XLink?, XPointer?, RDF のような XML 関連の実装を提供しています。