読者です 読者をやめる 読者になる 読者になる

Webエンジニア susumuis の技術ブログ

このブログの内容は個人の見解であり、所属する組織の公式見解ではありません

MayaaでHTML5のスマートフォンページを作る際にはまったこと

僕はMayaaが好きです。仕事でもかなり使っています。

今回、スマートフォンiPhoneおよびAndroid対応)向けECサイトのフロントエンドに、Mayaaを使用しました。そこではまったことを報告します。

metaタグにContentTypeが省略できるようになったため、ドキュメント判別の手段が減ってしまった

HTML5では、

<meta charset="UTF-8">

のような書き方が許されるようになりました。

従来は

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

という書き方をしていました。
これで何が問題なのかというと、Mayaa自体がこのContent-Type指定を読んでいてそれによって処理を判別(例えばapplication/xhtml+xmlかどうかなど)もしているので、動作が異なってしまう場合があります。

私たちの場合は、内部的な事情で、テンプレートファイルの拡張子に.xhtmlを使用していたため、すべてのContentTypeヘッダがapplication/xhtml+xmlになってしまい、ブラウザのバリデーションエラーで画面が真っ白になるという現象が発生しました。

回避方法は、前者の省略記法を使用せず、後者の従来通りの書き方をすることです。この書き方はHTML5文法としても正式です。

aタグがブロック要素を包含できるようになったのに、うまくいかない

この問題は意外と深かったです。テンプレートに

<a href="javascript:alert('hello');">
       <p>aaa</p>
       <p>aaa</p>
</a>

のように記述すると、実行時に勝手に以下のように書き換えられてしまいます。

<a href="javascript:alert('hello');">
       </a><p><a href="javascript:alert('hello');">aaa</a></p>
       <p>aaa</p>

これは、Mayaa依存ライブラリのNekoHTMLが、パースした段階でDOMツリーを再構成してしまうためで、NekoHTMLHTML5に対応していないため、XHTMLやHTML4以前の仕様に基づいて、DOMツリーを構成してしまいます。

この件について、現時点で一番良い回避法は、
http://ml.seasar.org/archives/mayaa-user/2011-March/000923.html
こちらで対応してくださった方法を使用することです。しかし、この場合は、imgやbrなども含めて必ず閉じタグを書かなければなりません。テンプレートコーディング者が第三者の場合などその徹底が難しい場合は使用が難しいと思います。

NekoHTMLについては、本家MLに問い合わせたところ、最新版でもHTML5への特別な対応はしていないとの返答をいただきました。

最終手段として、私は、NekoHTMLのソースを直接書き換えました。修正箇所は、Mayaaが使用しているNekoHTML-0.9.5をベースとして、

org.cyberneko.html.HTMLElements の、

184:     new Element(A, "A", Element.INLINE, BODY, null),

184:     new Element(A, "A", 0, BODY, null),

に書き換えることです。

NekoHTMLにはテストコードが付属しているので、実行してみたところ、2箇所でエラーになりました。

test:
[tester] Parsing test files and generating output...
[tester] Comparing parsed output against canonical output...
[tester] test36.html:5 strings don't match
[tester] [in: )A]
[tester] [out: (P]
[tester] test50.html:5 strings don't match
[tester] [in: )A]
[tester] [out: (P]
[tester] Finished with errors.

BUILD FAILED

これは、まさに今回の修正の対象だったので、テストケースを修正します。
/data/html/canonical/test36.html
修正前:

(HTML
(BODY
(A
Aname foo
)A
(P
(A
Aname foo
"Blah
)A
)P
)BODY
)HTML

修正後:

(HTML
(BODY
(A
Aname foo
(P
"Blah
)P
)A
)BODY
)HTML

/data/html/canonical/test50.html
修正前

(HTML
(BODY
(A
Ahref foo
)A
(P
(A
Ahref foo
"Blah
)A
)P
)BODY
)HTML

修正後

(HTML
(BODY
(A
Ahref foo
(P
"Blah
)P
)A
)BODY
)HTML

test:
[tester] Parsing test files and generating output...
[tester] Comparing parsed output against canonical output...
[tester] Done.

BUILD SUCCESSFUL

これで、独自にビルドしたnekohtmlのjarをアプリのlibにコピーし、nekohtml-0.9.5.jarを削除すれば差し替え完了です。