HTML2SafeHTML を XHTML対応(?)
先日のエントリで、COREBlog の XHTML対応 のような生意気なことを書いた。
ここで言いたかったのは、正しい XHTML は、すべてのエレメントに閉じタグが必要だと言う事。
たとえば、HTMLにおける、<br> タグは、<br></br> と記述するか、
<br /> と記述する必要がある。
原因は、stripogram/html2safehtml.py にあった。というよりも、safehtmlと言っている訳だから、これで良いのだ。safexhtmlを COREBlog が採用すべきなのである。
ということで、簡単なパッチを作ってみた。
(追記: 本日 9:40 patch の間違いを修正した。もし、9:40 以前に参考にされた方がいるなら、もう一度読み直していただきたい。)
以下の修正を、lib/python/Products/COREBlog/stripogram/html2safehtml.py に施す。
*** html2safehtml.py.org Mon Feb 2 06:11:22 2004
--- html2safehtml.py Mon Feb 2 09:00:11 2004
***************
*** 57,67 ****
if tag not in self.never_close:
self.openTags.append(tag)
! self.result = self.result + '>'
def handle_endtag(self, tag):
try:
while tag != self.openTags[-1] and self.openTags[-1] in self.can_close:
self.openTags.pop()
--- 57,73 ----
if tag not in self.never_close:
self.openTags.append(tag)
! if tag in self.never_close:
! self.result = self.result + ' />'
! else:
! self.result = self.result + '>'
def handle_endtag(self, tag):
try:
+
+ if tag in self.never_close:
+ return
while tag != self.openTags[-1] and self.openTags[-1] in self.can_close:
self.openTags.pop()
とりあえず、動いているみたいだが、しばらく様子を見ようと思っている。
パッチの意味
せっかくなので、簡単に説明しておこう。(非常に読みにくい文章だと思うので、ご注意を)
HTMLParse は XHTMLにも対応しており、<br /> のようなタグの場合、きちんと空のエレメントとして処理しようとしている。これが、HTMLParser::handle_startendtag メソッドだ。
# Overridable -- finish processing of start+end tag: <tag.../>
def handle_startendtag(self, tag, attrs):
self.handle_starttag(tag, attrs)
self.handle_endtag(tag)
一方、HTML2SafeHTMLのほうでは、handle_starttag メソッドがオーバーライドされていて、never_close リストに登録されたエレメントは、閉じタグを出力しないようにしている。(html2safehtml.py の 57行目)
if tag not in self.never_close:
self.openTags.append(tag)
また、self.never_close リストは、以下のようになっている。(html2safehtml.py の 15行目)
never_close = ['br','wbr','hr','input','isindex','base','meta','img']
もう少し具体的に説明すると、閉じタグが必要なエレメントの場合、self.openTags リスト(スタック)に タグを登録しておき、handle_endtag (html2safehtml.py の 65行目) や、cleanup (html2safehtml.py の 78行目) で閉じタグを(openTagsスタックに登録されていれば)出力しているのだ。
そこで、never_close に登録されている タグは、全て <タグ /> のように出力するようにした。
これによって、handle_endtag で問題が発生する。問題の個所は、以下の部分である。(html2safehtml.py の 66行目)
while tag != self.openTags[-1] and self.openTags[-1] in self.can_close:
self.openTags.pop()
たとえば、<p>ほげほげ<br />はげはげ</p> の場合に、openTagsスタックに br エレメントが登録されていないため、openTagsスタックに登録されているpエレメントを pop してしまうのだ。これによって、pエレメントの閉じタグが出力されなくなる。
この問題点の対策として、私の作成した patch では、never_close に登録されたエレメントの場合、handle_endtagを処理しないようにした。
もう一点考えなければならないのは、<br></br> のようなケースだが、HTMLParser::handle_startendtag を呼び出す事と同じように、HTMLParser::handle_starttag, HTMLParser::handle_endtag が連続して呼び出される。従って、<br></br> は、<br /> のように変換される。今のところ、これは問題だとは思えないのでそのままにしておいた。
最後に注意
とりあえず、この patch をあてた状態では、正しい XHTMLしか処理できない。おかしな XHTMLを食わせた場合にはきちんとエラー処理をすべきだろう。この patch を参考にされる場合は、不具合などあればコメントいただきたい。
