Python:xml.etree.ElementTree

RDF からデータを取り出したいと思い、はじめて xml.etree.ElementTree モジュールを利用しました。ハマったのは、パス指定の名前空間部分。


参考にしたコードサンプルでは「.//タグ名」で子孫の要素を参照できると書いてあった。そこで、title のテキストを取得しようと思い、次のように記述したのだが。

if __name__ == "__main__":
  import xml.etree.ElementTree as etree
  source   = 'sample.rdf' 
  rootTree = etree.parse(source)
  title    = rootTree.findtext('.//title')
  print title.encode('utf-8','ignore')

何も出力されなかった。

名前空間を考えなければ、RDF は次のような構造。

rdf:RDF
  channel
    title
    link
    description
    iterms
      rdf:Seq
        rdf:li(rdf:resource)
  item
  item

そこで、イテレータで順番に各要素を参照してみた。

if __name__ == "__main__":
  import xml.etree.ElementTree as etree
  source='sample.rdf'
  rootTree=etree.parse(source)
  print rootTree #
  for i in rootTree.getiterator():
    if i.tag:#
      print 'tag : '+ i.tag

なぜか 「print rootTree」のように1行文字列を出力しておかないと、それ以降のものが出力されない。
また、tag がないノードもあるので、「if i.tag:」のように条件を付与する必要がある。
なお、属性もみたいときは、次の文を加えればよい。

    if i.attrib:
      print str(i.attrib)

上記のスクリプトを実行すると、次のような結果に。

<xml.etree.ElementTree.ElementTree instance at 0xe44490>
tag : {http://www.w3.org/1999/02/22-rdf-syntax-ns#}RDF
tag : {http://purl.org/rss/1.0/}channel
tag : {http://purl.org/rss/1.0/}title
tag : {http://purl.org/rss/1.0/}link
tag : {http://purl.org/rss/1.0/}description
tag : {http://purl.org/dc/elements/1.1/}publisher
tag : {http://purl.org/dc/elements/1.1/}date
tag : {http://purl.org/dc/elements/1.1/}language
tag : {http://purl.org/rss/1.0/}items
tag : {http://www.w3.org/1999/02/22-rdf-syntax-ns#}Seq
tag : {http://www.w3.org/1999/02/22-rdf-syntax-ns#}li
tag : {http://www.w3.org/1999/02/22-rdf-syntax-ns#}li
(中略)
tag : {http://purl.org/rss/1.0/}item
tag : {http://purl.org/rss/1.0/}title
tag : {http://purl.org/rss/1.0/}link
tag : {http://purl.org/rss/1.0/}description
tag : {http://purl.org/dc/elements/1.1/}creator
tag : {http://purl.org/dc/elements/1.1/}publisher
tag : {http://purl.org/dc/elements/1.1/}date
tag : {http://purl.org/dc/elements/1.1/}rank
tag : {http://purl.org/dc/elements/1.1/}point
tag : {http://purl.org/dc/elements/1.1/}arrow
tag : {http://purl.org/rss/1.0/}item
(以下略)

上の結果、tag の値というのは、名前空間付であることがわかった。
一番最初のスクリプトを次のように書き換えた。

  title = root.findtext('.//{http://purl.org/rss/1.0/}title')


ちゃんとタイトルが表示された。
名前空間を押さえなければいけないことがわかりました。