XMLに実体参照が含まれてパースエラーになってしまう件。

自分で書いたプログラムを使って吐き出したRSSを、PHPのSimpleXmlで読み込もうとするとなぜかパースエラーになる。なぜなんだ…と散々苦悩したんですけど、これ結構メジャーな問題なんですね。今まで気付かなかったことが逆に怖い。


以下、一応まとめ。



問題の根本的な原因

HTMLとXMLとでは利用できる実体参照の範囲が異なるため。HTMLと同じ調子でエスケープしてXMLに流し込むとエラーになってしまいます。

特にDTDを指定しない場合、XMLで使用できる実体参照は以下のものだけです。
  • &(&)
  • &lt;(<)
  • &gt;(>)
  • &quot;(")
  • &apos;(')
一方、エラーが出たXMLには以下が含まれていました。
  • &infin;(∞)
  • &hellip;(…)
  • &times;(×)
なるほど。


解決策

解決策としては次のどれか。
  1. DTDを読み込む
  2. &を&amp;に変換する
  3. 実体参照を数値参照に変換する(&infin; → ∞)
  4. <![CDATA[ ]]>で括る
根本的には2か3を考えるべきなんでしょうけど、ちゃんとやろうとすると自分で表なり配列なり使って総当たりで変換する必要があって結構面倒なので…やめました(1はどれ読んだらいいか解りませんでした)。PHPまたはフレームワーク内にそれに対応する関数があったら良かったけど見つからなかったし。そういうわけで、<![CDATA[ ]]>であっさり括って解決。今後問題が出ないとは限りませんがとりあえず何とかなってるっぽい。



参考リンク

これに関しては以下を参考にさせていただきました。ありがとうございます。

ここギコ!: RSS内の実体参照
文字実体参照(実体参照).数値文字参照(文字参照)を RSS1.0 で表示する – 日々のこと