動かざることバグの如し

近づきたいよ 君の理想に

RubyのREXML::Document でXMLをパースする

rubyXMLを扱いたい人生だった

環境

概要

RubyXMLをパースする手段はいろいろあるが、ここでは特にライブラリを追加インストールすることなく、標準ライブラリだけで実行可能なREXML::Documentを使うことにした。

で「ruby XML」でググると一番上に以下のサイトがヒットするのだが、

残念ながらはてなダイアリーが終了して見れなくなるので、自分用の備忘録も兼ねてメモ

読み込み

ここでは例としてニコニコ動画に使われているXMLを読むとする。

require "rexml/document"
require "open-uri"
url = "http://ext.nicovideo.jp/api/getthumbinfo/sm2959233"
doc = REXML::Document.new(open(url).read)
p doc

子要素の取得

doc.elements

子要素を指定して取得

先頭に「//」から始めることで明示的にrootから始まることを意味する。で[]の中でパスを書くだけ。で、textで文字列取得

doc.elements['//nicovideo_thumb_response/thumb/video_id'].text
> sm2959233

属性を取得

属性(<>内の値)はattributesでhashで取得できる。

doc.elements['//nicovideo_thumb_response'].attributes
> {"status"=>status='ok'}

子要素をeachで回して取得

elements.eachで可能

doc.elements.each('//nicovideo_thumb_response/thumb/tags/tag') do |elm|
  
  p elm.text
  p elm.attributes 
  
end

特定の属性を持つ子要素だけをeachで回して取得

doc.elements.each('//nicovideo_thumb_response/thumb/tags/tag[@lock="1"]') do |elm|
  p elm.text
end

蛇足

ActiveSupportのcore_extを使うとXMLをHashに変換することができる。

require "rexml/document"
require "open-uri"
url = "http://ext.nicovideo.jp/api/getthumbinfo/sm2959233"
doc = REXML::Document.new(open(url).read)
hash = Hash.from_xml(doc.to_s)
pp hash

以下のようなhashを得られる。一部の属性がカットされてしまっている点には注意が必要だが、せこせこパースするぐらいならこっちのほうが開発のスピードは早いかもしれない(

{"nicovideo_thumb_response"=>
  {"status"=>"ok",
   "thumb"=>
    {"video_id"=>"sm2959233",
     "title"=>"ニコニコ動画流星群",
     "description"=>
      "ニコニコ動画で人気のある名曲(極一部、趣味)を繋いでひとつの曲にしてみました(約4回目)。mylist/1535765user/145217",
     "thumbnail_url"=>"http://tn.smilevideo.jp/smile?i=2959233",
     "first_retrieve"=>"2008-04-11T05:05:52+09:00",
     "length"=>"14:05",
     "movie_type"=>"mp4",
     "size_high"=>"40265605",
     "size_low"=>"38847215",
     "view_counter"=>"6396448",
     "comment_num"=>"1450707",
     "mylist_counter"=>"108509",
     "last_res_body"=>
      "これ見ると平成最後が やっぱりニコニコ最高 いくぞ! 平成 ★=ー おっくせんまん!おっ おっくせんまん!おっ おっくせんまん!おっ おっくせんまん!おっ おっくせんまん 鈍痛☆鈍痛☆... ",
     "watch_url"=>"https://www.nicovideo.jp/watch/sm2959233",
     "thumb_type"=>"video",
     "embeddable"=>"1",
     "no_live_play"=>"0",
     "tags"=>
      {"domain"=>"jp",
       "tag"=>
        ["音楽",
         "アレンジ",
         "ニコニコ動画流星群",
         "空気の読めるWMP",
         "ニコニコメドレーシリーズ",
         "600万再生",
         "simoyuki",
         "SP1時代の奇才",
         "ありがとう",
         "原点にして頂点",
         "重要ニコニコ文化財"]},
     "genre"=>"音楽・サウンド",
     "user_id"=>"145217",
     "user_nickname"=>"しも",
     "user_icon_url"=>
      "https://secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/defaults/blank_s.jpg"}}}

サンプルに使ったXML

<nicovideo_thumb_response status="ok">
  <thumb>
    <video_id>sm2959233</video_id>
    <title>ニコニコ動画流星群</title>
    <description>
ニコニコ動画で人気のある名曲(極一部、趣味)を繋いでひとつの曲にしてみました(約4回目)。mylist/1535765user/145217
</description>
    <thumbnail_url>http://tn.smilevideo.jp/smile?i=2959233</thumbnail_url>
    <first_retrieve>2008-04-11T05:05:52+09:00</first_retrieve>
    <length>14:05</length>
    <movie_type>mp4</movie_type>
    <size_high>40265605</size_high>
    <size_low>38847215</size_low>
    <view_counter>6396439</view_counter>
    <comment_num>1450707</comment_num>
    <mylist_counter>108509</mylist_counter>
    <last_res_body>
これ見ると平成最後が やっぱりニコニコ最高 いくぞ! 平成 ★=ー おっくせんまん!おっ おっくせんまん!おっ おっくせんまん!おっ おっくせんまん!おっ おっくせんまん 鈍痛☆鈍痛☆...
</last_res_body>
    <watch_url>https://www.nicovideo.jp/watch/sm2959233</watch_url>
    <thumb_type>video</thumb_type>
    <embeddable>1</embeddable>
    <no_live_play>0</no_live_play>
    <tags domain="jp">
      <tag category="1" lock="1">音楽</tag>
      <tag lock="1">アレンジ</tag>
      <tag lock="1">ニコニコ動画流星群</tag>
      <tag lock="1">空気の読めるWMP</tag>
      <tag>ニコニコメドレーシリーズ</tag>
      <tag>600万再生</tag>
      <tag>simoyuki</tag>
      <tag>SP1時代の奇才</tag>
      <tag>ありがとう</tag>
      <tag>原点にして頂点</tag>
      <tag>重要ニコニコ文化財</tag>
    </tags>
    <genre>音楽・サウンド</genre>
    <user_id>145217</user_id>
    <user_nickname>しも</user_nickname>
    <user_icon_url>
https://secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/defaults/blank_s.jpg
</user_icon_url>
  </thumb>
</nicovideo_thumb_response>