今日も元気にテクニカル

技術情報書きたいけど本ブログに書きたくないからこんな名前になりました。

昨日の続き-XMLの読み出し

require 'pp'
require 'kconv'
require 'rexml/document'
include REXML

doc = REXML::Document.new File.open("newsing.xml","r")
arr1 = []

doc.root.elements.each("//item") do |item|
  item.elements.each do |elem|
    arr2 = []
    arr2 << elem.text.tosjis if elem.has_text? && elem.name != "comments"
    if elem.name == "comments"
      elem.elements.each(".//comment") do |comment|
        arr3 = []
        comment.elements.each do |elem|
          arr3 << elem.text.tosjis if elem.has_text?
        end
        arr2 << arr3
      end
    end
    arr1 << arr2
  end
end
pp arr1

#=> [[url1,title2...,[comment1]],[url2,title2...[comment2]]...]

昨日と違うのは#elementsメソッドをつけてelementsクラスに変更→#eachメソッドを使えるようにして、XPATHで要素を取り出してるってことかな。多少分かりやすくなってるはず。

…まぁ長考した結果全然構成変わってないじゃん、とツッコミ受けそうだけど、細かくしすぎても後々分かりにくいので取りあえずこれをベースにすることにする。(これよりコード量を少なくしようとすると、XMLの方を変更しないといけないのかなぁ。)

参考

名前指定でコードを取り出すロジックも作ってみました。

require &#39;pp&#39;
require &#39;kconv&#39;
require &#39;rexml/document&#39;
include REXML

doc = REXML::Document.new File.open("newsing.xml","r")
arr1 = []

doc.root.each_element do |elem|
  arr2 = []
  arr2 << elem.elements["url"].text
  arr2 << elem.elements["title"].text
  arr2 << elem.elements["main_text"].text
  arr2 << elem.elements["picker"].text
  arr2 << elem.elements["picktime"].text
  arr2 << elem.elements["picktime"].text
  arr2 << elem.elements["pick_com"].text
  arr2 << elem.elements["picker_eval"].text
  arr2 << elem.elements["pt"].text
  if elem.elements["comments"]
    elem.elements["comments"].each_element do |elem|
      arr3 = []
      arr3 << elem.elements["commenter"].text
      arr3 << elem.elements["comtime"].text
      arr3 << elem.elements["com_eval"].text
      arr3 << elem.elements["com_text"].text
      arr3 << elem.elements["nicecomment"].text
      arr2 << arr3
    end
  end
  arr1 << arr2
end
pp arr1

いちいち "if elem.has_text?" って書くのが面倒になって挫折したけど、こっちの方が分かりやすいかもしれない。

# 配列の出力はppで出すのがお勧めです。

ちょっくらXPathの勉強

リファレンスとかあまり読まない僕ですが(←だめじゃん)、「対象ノードのコメント一覧を抽出する方法」を調べるためにがんばって読んでみた。

データベース連携からシステム統合まで、企業システムの「つなぐ」を実現|インフォテリア株式会社

これによると、

elem.elements.each("//comment") # rootノード以下の全てのcommentという子孫エレメント
elem.elements.each(".//comment") # コンテキスト(カレント)ノード以下の全てのcommentという子孫エレメント

らしいです。REXMLの使い方だけじゃなくXPathの知識と合わせて使わないといけないんだね><