ここのAtomをRailsのAtomFeedHelper#atom_feedで出力してたんですが、基本全て数値文字参照で出る。

エンコーディングに関係無く表示されるので正しくはあるんだろうけど、クロールされてるところ(Planet PHP Japanなど)ではもう一度エスケープがかかって数値の羅列になってしまう。

フィードクライアントとしては数値文字参照をHTMLとして解釈した上でエスケープする必要があるだろう。しかし、自分がクロールする側になったら正直、

「面倒だから数値文字参照などにせんでくれ・・・」

と思うだろう。

しかもそういったクライアントを通して見る第三者の人にとってはそんなサーバークライアント間のやり取りなどどうでもいいことで、単に

「文字化けうぜぇえええ」

である。

atom_feedメソッドでのHTMLのエスケープはたくさんのクラスを遡って、最終的にはここ(String#to_xs)でやってるらしい。

/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb:

class Fixnum
  XChar = Builder::XChar if ! defined?(XChar)

  # XML escaped version of chr
  def xchr
    n = XChar::CP1252[self] || self
    case n when *XChar::VALID
      XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
    else
      '*'
    end
  end
end

(...snip...)

class String
  # XML escaped version of to_s
  def to_xs
    unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
  rescue
    unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
  end
end

コメントを見ると、そもそもコレ自体XCharライブラリーというのを拝借しているものらしい。

Wikipediaによると、西欧22言語をサポートするISO-8859-1もCP1252も共にLatin1と呼ばれますが、IBM由来のMicrosoft Codepage(CP)では0×80から0×9Fの範囲の文字が拡張されています。(ユーロ、ダガーとか)

要はShift_JISとCP932みたいな問題がLatin1とCP1252にもあるんですな。

何のためのライブラリかというと、多言語化の時に問題になりそうなそのCP1252の拡張部分を適当な文字にマッピングするためのものらしい。(自動的にCP932で書いたら問題が起きそうなことが予想できる)

とりあえずUnicodeをUTF-8で使ってれば問題無いだろうということで下記の様に対処した。

config/initializers/rails_ext.rb:

class String
  def to_xs
    ERB::Util.html_escape(self)
  end
end

大丈夫かな?

Comments


Option