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/