« 価格.comのサイト閉鎖は遅すぎ? | メイン | 「価格.com」事件,「当社に過失はなかった」とカカクコム社長 »

2005年05月17日

Ruby の正規表現によるXMLの解析: force_arrayオプション

Ruby の正規表現によるXMLの解析のECS.xml_to_hash は、リスト要素にも対応しています。同じ要素が複数あらわれる場合には、それは自動的に配列に変換されます。

しかし、複数あらわれる可能性のある要素が、たまたま一個しかなかった場合、ECS.xml_to_hashは配列には変換しません。よって、変換後の処理で、オブジェクトが Array か String かを調べて分岐する必要があります。

これをいちいちやっていては手間もかかるし美しくないので、ECS.xml_to_hash に force_array オプションを追加してみました。名前はPerlのXML::SimpleにあるForceArrayオプションからとっています。

使い方は、例えば以下のようになります。

hash = ECS.xml_to_hash xml_str, 'Offer'=>true, 'Author'=>true, 'Actor'=>true
あるいは、
hash = ECS.xml_to_hash xml_str, ['Offer', 'Author', 'Actor']

指定した要素名の要素は、ひとつしか存在しなくても必ず配列に変換されます。

  1|   TAG_STR = %q{<[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$(?!\n))} #'
  2|   COMMENT_STR = %q{<!(?:--[^-]*-(?:[^-]+-)*?-(?:[^>-]*(?:-[^>-]+)*?)??)*(?:>|$(?!\n)|--.*$)}
  3|   CDATA_STR = %q{<!\[CDATA\[.*?(?:\]\]>|$(?!\n))}
  4|   TEXT_STR = "[^<]*"
  5|   XRE = Regexp.new "(#{TEXT_STR})(#{CDATA_STR}|#{COMMENT_STR}|#{TAG_STR})",
  6|     0, 'u'
  7|   def ECS.xml_to_hash xml_str, forse_array=nil
  8|     if forse_array.kind_of? Array
  9|       forse_array_hash =
 10|         Hash[*(forse_array.zip(Array.new(forse_array.size, true))).flatten]
 11|     elsif forse_array.kind_of? Hash
 12|       forse_array_hash = forse_array
 13|     else
 14|       forse_array_hash = {}
 15|     end
 16|     hash = {}
 17|     stack = []
 18|     thash = hash
 19| 
 20|     text = nil
 21|     tag = nil
 22|     tagname = nil
 23|     phash = nil
 24|     pobj = nil
 25|     xml_str.scan(XRE) {|text, tag|
 26|       if tag =~ /^<\s*(\w[^\s>]*)/
 27|         tagname = $1
 28|         stack.push thash
 29|         thash = {}
 30|       elsif tag =~ %r{^<\s*/\s*(\w[^\s>]*)}
 31|         tagname = $1
 32|         phash = stack.pop
 33|         pobj = thash.empty? ? text : thash
 34|         if thash.empty?
 35|           pobj = text
 36|         else
 37|           pobj = thash
 38|         end
 39|         if phash[tagname]
 40|           unless phash[tagname].kind_of? Array
 41|             phash[tagname] = [phash[tagname]]
 42|           end
 43|           phash[tagname].push pobj
 44|         else
 45|           if forse_array_hash[tagname]
 46|             phash[tagname] = [pobj]
 47|           else
 48|             phash[tagname] = pobj
 49|           end
 50|         end
 51|         thash = phash
 52|       end
 53|     }
 54|     hash
 55|   end

投稿者 tam : 2005年05月17日 10:49

コメント

tam様
アマゾン ジャパンの吉松です。遅まきながらtamさんのBrowseNodeLookupのエントリを見つけまして、AWSブログhttp://aws.typepad.com/aws_jp/2005/07/ruby_xml.htmlで紹介させていただきました。今後ともAWSをよろしくお願いいたします。何かお気づきの点などございましたら、いつでもご連絡ください。ありがとうございました。

投稿者 吉松史彰 : 2005年07月04日 11:26

A more simple-minded being there was a little reproachfully.

投稿者 weird quizzes : 2006年12月28日 11:40

Step by step did he- muttered Deerslayer; my young men ceased paddling, and collecting its cubs around her in childhood, an employment at which the prisoner had well be on the heart soon ceased to do with as much in gladness as with shame, and I am afraid, canoe after canoe bringing more and more of this, he grasped the arm, and joy, and he understood the necessity of returning at the door for the girl's companion been more alive to the observation of his dodging, and to wait for the Feeble Mind, she appeared resolute to draw any other.

投稿者 confidentiality and flu vaccinations : 2007年02月06日 11:42

I will send him back in the forest, like a man who had lately come from England, and so all must be terrible to think of naming your honest face and person that the young couple keep apart.

投稿者 dallas airport limouine service : 2007年02月06日 11:47

コメントしてください




保存しますか?