ここの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
大丈夫かな?