その時々

その時々で違うんです。特に決まっていないんです。

PythonでXMLを触ってみる3 minidomね

今回は子ノードをトラバースしてみます。

Sample.xml

<?xml version="1.0" encoding="UTF-8"?>
<cars>
  <car>
    <name>乗用車</name>
    <price>150</price>
  </car>
  <car>
    <name>トラック</name>
    <price>500</price>
  </car>
  <car>
    <name>オープンカー</name>
    <price>200</price>
  </car>
</cars>

minidom3.py

# _*_ coding:UTF-8 _*_
import xml.dom.minidom

def walk(node):
    n = node.firstChild
    while n:
        print n.nodeName
        n = n.nextSibling
    
doc = xml.dom.minidom.parse('Sample.xml')
root = doc.documentElement
walk(root)

このスクリプトを実行すると
car
car
car
となるのかと思っていたのですが、

実行結果

$ python minidom3.py
#text
car
#text
car
#text
car
#text

こんなふうになりました。
これは結構嵌る原因になりそうです。
何が入っているかといいますと
pythonインタプリタで見てみましょう。

>>> import xml.dom.minidom
>>> doc = xml.dom.minidom.parse('Sample.xml')
>>> root = doc.documentElement
>>> root.childNodes
[<DOM Text node "u'\n  '">, <DOM Element: car at 0xb74673ec>, <DOM Text node "u'\n  '">, <DOM Element: car at 0xb746756c>, <DOM Text node "u'\n  '">, <DOM Element: car at 0xb74676ec>, <DOM Text node "u'\n'">]

どうも改行までもが一つのテキストノードとしてパースされるようなのです。
なので前回writexmlで1行に出力されてしまう原因が分ったような気がします。

それではElementのみ表示するようにしてみます。

minidom3.py

# _*_ coding:UTF-8 _*_
import xml.dom, xml.dom.minidom

def walk(node):
    n = node.firstChild
    while n:
        if n.nodeType == xml.dom.Node.ELEMENT_NODE:
            print n.nodeName
        n = n.nextSibling
    
doc = xml.dom.minidom.parse('Sample.xml')
root = doc.documentElement
walk(root)

実行結果

$ python minidom3.py
car
car
car

さらに子ノードを辿るには再帰呼出しを行なえば簡単です。

minidom3.py

# _*_ coding:UTF-8 _*_
import xml.dom, xml.dom.minidom

def walk(node):
    n = node.firstChild
    while n:
        if n.nodeType == xml.dom.Node.ELEMENT_NODE:
            print n.nodeName
            walk(n)
        n = n.nextSibling
    
doc = xml.dom.minidom.parse('Sample.xml')
root = doc.documentElement
walk(root)

実行結果

$ python minidom3.py
car
name
price
car
name
price
car
name
price


それでは空白・改行以外のテキストノードも表示してみます。

minidom3.py

# _*_ coding:UTF-8 _*_
import xml.dom, xml.dom.minidom

def walk(node):
    n = node.firstChild
    while n:
        if n.nodeType == xml.dom.Node.ELEMENT_NODE:
            print n.nodeName
            walk(n)
        elif n.nodeType == xml.dom.Node.TEXT_NODE and len(n.nodeValue.strip()) != 0:
            print n.nodeValue
        n = n.nextSibling
    
doc = xml.dom.minidom.parse('Sample.xml')
root = doc.documentElement
walk(root)

実行結果

$ python minidom3.py
car
name
乗用車
price
150
car
name
トラック
price
500
car
name
オープンカー
price
200

COMPLETE!!