From: Maehara Masahide(前原正英) <maehrm / miyazaki-c.ed.jp> Subject: [ruby-list:45287] Hpricotでの疑問点(inner_html) Date: Thu, 31 Jul 2008 15:39:29 +0900 るびきちです。 > 以下を実行した際,「Ruby home page」と出力されることを期待していたので > すが,画面には,「ruby home page」と表示されます。 結論から言うと Hpricot::Elem#inner_html= を使えばうまくいきます。 putsすると修正が反映されます。 require 'rubygems' require 'hpricot' doc = Hpricot('ruby home page') (doc/:a).each do |ele| ele # => {elem "ruby home page" } ele.inner_html = ele.inner_html.gsub(/ruby/, "Ruby") ele.class # => Hpricot::Elem ele.inner_html # => "Ruby home page" end puts doc # >> Ruby home page ちなみに、Hpricot::Doc#/は該当するツリーすべてを取得しますが、Hpricot::Doc#atは 最初に見付かったもののみを取得します。 > 何故だろうと思い、hpricot-0.6/lib/hpricot/elements.rbを見てみたところ, > inner_htmlメソッドがあり,そこでは, > map { |x| x.inner_html }.join > というような配列に対する処理をやっているので,gsub!できないんだなと理 > 解したつもりなのですが,このinner_htmlは,Elements#inner_htmlです。 実は Hpricot::Elem#inner_html の実体は Hpricot::Traverse#inner_html です。 hpricot/modules.rb よりこんな定義になっているからです。 module Hpricot module Traverse end module Container::Trav; include Traverse end class Elem; module Trav; include Container::Trav end; include Trav end end # それにしてもまわりっくどい。いったいなんの意図が… で、hpricot/traverse.rbを見てみると、こうなっています。 module Hpricot module Traverse def html(inner = nil, &blk) if inner or blk altered! case inner when Array self.children = inner else self.children = Hpricot.make(inner, &blk) end reparent self.children else # ここを通る if respond_to? :children children.map { |x| x.output("") }.join end end end alias_method :inner_html, :html alias_method :innerHTML, :inner_html end end Hpricot::Elemは children メソッド(アクセサ)を持っているのでmap/joinしています。 だから、gsub!ができないのです。 おそらく inner_html をアクセサと勘違いしたのでしょう。 > 以下のように,eleは,Hpricot::Elemなので,ele.inner_htmlが実行できるの > が不思議な感じがします。 > p ele.class #=> Hpricot::Elem > p ele.inner_html そうですか? Hpricot::Elem はHTMLの要素(タグと内容)なのでinner_htmlが実行できても 不思議じゃないです。 -- rubikitch Blog: http://d.hatena.ne.jp/rubikitch/ Site: http://www.rubyist.net/~rubikitch/