これは Mayaa Advent Calendar 2015 の17日目です。昨日は「Mayaaで独自Processorを作ろう!」でした。
寒くなってきました。いよいよクリスマスまでカウントダウンですね!
毎日書けるのか心配だったこのブログも残すところあと1桁となり、終わってしまうことがちょっとさみしく思います。とはいえ、一日たりとも中断せぬよう、最後まで引き締めて行きます。
なお、Mayaaアドベントカレンダーはまだ参加者を募集しています!
Mayaaに慣れた僕がシリーズ開始
さて、今日から、Mayaa以外のテンプレートエンジンを試すシリーズを始めたいと思います。
Mayaa以外にもデザイナーとプログラマーの協業をうたったテンプレートエンジンは多数あります。それらを実際に試してみて、3日目から紹介した「いしがみメソッド」を適用できるか検証していきます。
第一回はMayaaの影響を受けて開発されたと言われる、Mixer2を試してみたいと思います。
Mixer2とは
Mixer2はJavaアプリケーション用テンプレートエンジンです。テンプレートはXHTMLで書きます。 100% pureな、XHTMLとCSSです。(html5もXML構文で書けば使えます)
と掲げられています。
テンプレートをXHTMLで書くという点がMayaaと共通しています。Mayaaと異なる点は、mayaaファイルというような独自の定義ファイルは存在せず、すべてJavaで制御することです。すべてJavaにすることでフロントのJUnitテストを可能であることをうたっています。
HelloWorldしてみる
Mixer2はMavenを使うことを推奨しているようです。jarファイル単体の配布はここでしているようですが、古いバージョンで止まっています。
POMに以下を追加しましょう。
<dependencies>
<dependency>
<groupId>org.mixer2</groupId>
<artifactId>mixer2</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
Mixer2 - TIPSによると、Mixer2EngineはSingletonとして扱うべきのようですので、はじめからSingletonにしておきます。
public class Mixer2EngineSingleton {
private static Mixer2Engine m2e = new Mixer2Engine();
public static Mixer2Engine get() {
return m2e;
}
}
テンプレートファイルを/WEB-INF/view/hello.xhtmlにおいてみます。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>たいとる</title>
</head>
<body>
<span id="HELLO_HERE">ハローワールド</span>
</body>
</html>
mixer2はm:idのような独自の名前空間ではなく、id属性を使うことを推奨しています。id属性だと複数使い回すことができないので、m:idのような使い方をするなら、class属性を使うことになるかもしれません。
また、XHTMLの文法上、titleタグにid属性を付けることは正しくないので、この部分も悩ましいところではあります。
そして、以下のようなServletを書けば、画面に「こんにちはMixer2」と表示されます。
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Mixer2Engine m2e = Mixer2EngineSingleton.get();
Html html = m2e.loadHtmlTemplate(getServletContext().getResourceAsStream("/WEB-INF/view/hello.xhtml"));
html.getById("HELLO_HERE", Span.class).replaceInner("こんにちはMixer2");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
response.getWriter().print(m2e.saveToString(html));
} catch (TagTypeUnmatchException e) {
e.printStackTrace(response.getWriter());
}
}
}
Mayaaと違って、Servletと疎結合になっています。そのため、文字コードやContentTypeなどは自分で指定してあげる必要があります。
Mixer2でいしがみメソッドを適用する
m:id含め、プログラム都合の識別子は常に大文字を使う
これは、プログラム制御用のid, class属性を常に大文字にすることで対応できます。
m:idのする仕事を4種類に限定する
同上です。ただし、id属性は、テンプレート内で一度しか使えないので、class属性を使うことが多くなると思います。
class属性を使った場合、getDescendants
で検索をするのですが、常に全DOMを走破するとオーバーヘッドが大きいかもしれません。
(Mayaaの場合、DOMを使わずSAXのように先頭からトラバースしていく方式なので、この問題がない一方xpath指定の効率が非常に悪くなっています。)
4種類の実装方法はルールに従う
これらは、毎回タグ操作をゴリゴリ書くのではなく、ある程度ユーティリティ化することによって、定型化することができると思います。
LOOP系のm:idはindexには長い名前を使い、maxを十分に大きな値を設定する
Mixer2の場合はプログラミングをJava内のスコープで行うのでこのような問題はありません。
writeプロセッサーでエスケープを解除するときは全部する
replaceInnerメソッドは常にエスケープしてしまうみたいなので、エスケープして欲しくない場合は別の方法が必要になりそうです。
tableタグだけは特別に扱う
これは、テンプレートエンジンというより、HTMLの仕様上の問題点なので、Mixer2でも同じ課題があります。
m:idをパラメータ対応にする
タグの属性は getOtherAttributes()
で取得できます。こんな感じで取得することができます。
span.getOtherAttributes().get(new QName("number"))
PathAdjusterを効果的に使う
Mixer2にもPathAdjusterがあります。仕様はMayaaのそれに似ているようです。
ヘッダー・フッター・共通部品はiframeタグをうまく使う
この部分は部分マーシャルを使ってうまく行くのではないかと思います。
テンプレート上のコメントは、ソース表示時に見えないようにする
Mixer2ではそもそもコメントが全部消えます!
単語はなるべくテンプレート側に書く
これは問題ないように思います。
nekoHTMLパーサーをいじる
初めからHTML5対応です。
まとめ
触ってみた感想として、Mayaaよりも、原始的な単機能のテンプレートエンジンという感じがしました。そのまま使っても、デザイナーと協業まで持っていくのは厳しいと思います。
また、タグの構造に対して厳密なコードを書く必要があるので、出来上がったテンプレートのタグの構造を後からプログラムの変更なしに変更するということには制約が多いように思います。
Mixer2を更にベースにして、独自フレームワークを構築することが必要になってくると思われます。
Mixer2の良い点は逆に、Servletと結合がないために単体で動いてしまうことです。サーバーサイド側でHTMLを整形するならJavaとの相性が非常によく、型安全でテスタブルにコーディングできるのは嬉しいです。
全体のテンプレートエンジンとして使うより、システムにmixer2を読み込んでおいて、HTMLを部分的に整形したり、Mayaaと組み合わせて部品をMixer2で作るといったこともというような合わせ技も検討の余地があるかもしれません。
思ったよりもMayaaと競合しない技術ではないかと思いました。