REXML と Libxml-Ruby とのエンティティ出力比較

REXML で大きな XML ファイルを処理したらあまりにも遅かった。Ruby で書かれているのでいたし方ないんですが。もちろん REXML は標準でついているし、手軽に使えて良いという大きなメリットがあるけど、行う処理が数時間レベルなので速くしたい。そこで Libxml http://libxml.rubyforge.org/ を試すことに。 行うのは XML → XML 変換なので、エンティティの出力が気になった。そこで次のようなコードを実行して、結果を比較してみる。 テストしたコード 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #!/usr/bin/env ruby # require 'rubygems' require 'xml/libxml' require 'rexml/document' str =<<EOS <?xml version="1.0" encoding="UTF-8"?> <root> <title>Tosshi&apos;s メモ書き</title> <array> <item attr='&apos;'> &lt;html&gt; &apos;TAG&quot; </item> <item attr="&quot;"><!\[CDATA\[ CDATA &lt;html&gt; &apos;TAG&qout; <>"' \]\]></item> </array> </root> EOS puts <<EOS \[ libxml-ruby \] EOS xp = XML::Parser.new xp.string = str libxmldoc = xp.parse puts "document :" puts libxmldoc node = libxmldoc.root.find_first("title") print "Node :" puts node print "content :" puts node.content print "child.to_s:" puts node.child.to_s libxmldoc.root.find("array/item").each do |item| print "Node :" puts item print "content :" puts item.content print "child.to_s:" puts item.child.to_s end puts <<EOS \[ REXML \] EOS rexmldoc = REXML::Document.new(str) puts "Document :" puts rexmldoc el = rexmldoc.root.elements\["title"\] print "Element :" puts el print "text :" puts el.text print "get_text :" puts el.get_text rexmldoc.root.elements.each("array/item") do |item| print "Element :" puts item print "text :" puts item.text print "get_text :" puts item.get_text end 結果 libxml はアポストロフィとダブルクォートを必要なときだけ実体名にエスケープする。 REXML は属性値は固定でアポストロフィで囲い、アポストロフィとダブルクォートは必ず実体名にエスケープする。 $ ruby testxml.rb \[ libxml-ruby \] Document : <?xml version="1.0" encoding="UTF-8"?> <root> <title>Tosshi's メモ書き</title> <array> <item attr="'"> &lt;html&gt; 'TAG" </item> <item attr="&quot;"><!\[CDATA\[ CDATA &lt;html&gt; &apos;TAG&qout; <>"' \]\]></item> </array> </root> Node :<title>Tosshi's メモ書き</title> content :Tosshi's メモ書き child.to_s:Tosshi's メモ書き Node :<item attr="'"> &lt;html&gt; 'TAG" </item> content : <html> 'TAG" child.to_s: &lt;html&gt; 'TAG" Node :<item attr="&quot;"><!\[CDATA\[ CDATA &lt;html&gt; &apos;TAG&qout; <>"' \]\]></item> content : CDATA &lt;html&gt; &apos;TAG&qout; <>"' child.to_s:<!\[CDATA\[ CDATA &lt;html&gt; &apos;TAG&qout; <>"' \]\]> \[ REXML \] Document : <?xml version='1.0' encoding='UTF-8'?> <root> <title>Tosshi&apos;s メモ書き</title> <array> <item attr='&apos;'> &lt;html&gt; &apos;TAG&quot; </item> <item attr='&quot;'><!\[CDATA\[ CDATA &lt;html&gt; &apos;TAG&qout; <>"' \]\]></item> </array> </root> Element :<title>Tosshi&apos;s メモ書き</title> text :Tosshi's メモ書き get_text :Tosshi&apos;s メモ書き Element :<item attr='&apos;'> &lt;html&gt; &apos;TAG&quot; </item> text : <html> 'TAG" get_text : &lt;html&gt; &apos;TAG&quot; Element :<item attr='&quot;'><!\[CDATA\[ CDATA &lt;html&gt; &apos;TAG&qout; <>"' \]\]></item> text : CDATA &lt;html&gt; &apos;TAG&qout; <>"' get_text : CDATA &lt;html&gt; &apos;TAG&qout; <>"'

2008年1月11日 · Toshimitsu Takahashi

Ruby の REXML と RSS Maker で Amazon で売れてるオライリー本のフィードを簡単に作る

使用したライブラリ open-uri rexml/document rss/maker RSS Parser ※ We retire raa.ruby-lang.org という Amazon Web Service を簡単に使えるライブラリも存在するが、単にリストを取得するだけなので今回は見送った。 コード RSS 2.0 で出力する。RSS::Maker.make(version) で引数にバージョンを入れて指定する。 Description にイメージと著者、出版日、価格を入れている。Author は複数タグあるため、カンマで結合。 同じようなものを仕事で Java で作ったことがあったが、Ruby などの Light Weight 言語の手軽さを知ってしまうと戻れない。 結果: http://feed.tilfin.net/amazon/oreilly-bestseller.xml 下記のコードでは、ファイル書き出しをコメントアウトして、CGIとしての動作を有効にさせている。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #!/usr/bin/env ruby # # Amazon O'Relly Sales Ranking # Rss feed # ################################# require 'open-uri' require 'rexml/document' require 'rss/maker' param = { 'Service' => 'AWSECommerceService', 'AWSAccessKeyId' => '☆アクセスキーID☆', 'AssociateTag' => '☆アソシエイトID☆', 'Operation' => 'ItemSearch', 'SearchIndex' => 'Books', 'ResponseGroup' => 'Medium', 'Sort' => 'salesrank', 'Publisher' => 'オライリー' } params = param.map do |key, value| "#{URI.encode(key)}=#{URI.encode(value)}" end.join("&") doc = nil open('http://webservices.amazon.co.jp/onca/xml?' \+ params) { |resp| doc = REXML::Document.new(resp) } rss = RSS::Maker.make("2.0") do |maker| maker.channel.title = "O'Reilly ベストセラー (Amazon)" maker.channel.description = "O'Reilly の Amazon.co.jp のセールストップ 10 を紹介" maker.channel.link = "http://feed.tilfin.net/amazon/orelly-bestseller.xml" number = 0 doc.elements.each("/ItemSearchResponse/Items/Item") do |item| itmat = item.elements\["ItemAttributes"\] number += 1 entry = maker.items.new_item entry.title = number.to_s + '. ' \+ itmat.elements\["Title"\].text entry.link = item.elements\["DetailPageURL"\].text desc = nil item.elements.each("MediumImage") { |img| desc = <<EOS <img src="#{img.elements\["URL"\].text}" width="#{img.elements\["Width"\].text}" height="#{img.elements\["Height"\].text}"><br> EOS } desc += itmat.elements.each("Author") { |a| a.text }.join(", ") \+ " (著)" desc += "<br>発売日:" \+ itmat.elements\["PublicationDate"\].text.gsub(/-/, '/') desc += "<br>" \+ itmat.elements\["ListPrice/FormattedPrice"\].text entry.description = desc entry.date = Time.now end end print "Content-Type:application/rss+xml\\r\\n\\r\\n" print rss #open("oreilly-bestseller.xml", "w") { |out| \# out.print rss #} #``` ※IE7だと application/rss だけではフィードだと認識されなかった。

2008年1月3日 · Toshimitsu Takahashi