カジュアルな技術ノート

小難しい技術のお話をできるだけわかりやすく...

【Thymeleaf】Thymeleaf の Dialect でのタグ編集まとめ

Thymeleaf の Dialect を実装、オリジナルのタグや属性値を使ってよく使う DOM 要素を短く書きたいといったことはよくあるケースだと思います。

IElementTagProcessor を使い実装するときは doProcess メソッドを実装することで処理を書いていきますが、そこでタグを編集する方法をまとめます。

doProcess メソッドの処理の流れ

IElementTagProcessor の doProcess メソッドの大まかな実装の流れを書きます。

protected void doProcess(ITemplateContext context, IProcessableElementTag tag, IElementTagStructureHandler structureHandler) {
        // ①タグ作成の準備
        IModelFactory modelFactory = context.getModelFactory();
        IModel model = modelFactory.createModel();

        // ②ここからごにょごにょ新しいタグを作る
        model.add(modelFactory.createStandaloneElementTag("input", "type", "text"));  // テキストボックスを作るコード例

        // ③作った新しいタグを追加・古いタグに対して置換など
        structureHandler.replaceWith(model, false);  // 置換するコード例
}

本記事では主に②〜③でどんなことができるのかをまとめます。

タグ編集 tips 目次

新しいタグ作成してみる

新しいタグを作るには IModelFactory クラスの以下メソッドを使用する。

基本的な生成メソッド
メソッド 生成するもの
createOpenElementTag 開始タグを作成
createCloseElementTag 終了タグを作成
createStandaloneElementTag タグを作成
createText テキストを挿入

基本的にはレンダリングされる View の各行ごとに必要なメソッドでタグやテキストを追加してあげるイメージ。

上で紹介したメソッドを使った例として次のようなログインフォームを作ることを考える。

<form>
  <p>username</p>
  <input name="username">
  <p>password</p>
  <input name="password">
  <input type="submit">
</form>

これを生成するためのコード例は次。

// form の開始タグの作成
model.add(modelFactory.createOpenElementTag("form"));
// username の p タグと input タグの作成
model.add(modelFactory.createOpenElementTag("p"));
model.add(modelFactory.createText("username"));
model.add(modelFactory.createCloseElementTag("p"));
model.add(modelFactory.createStandaloneElementTag("input", "name", "username"));
// password の p タグと input タグの作成
model.add(modelFactory.createOpenElementTag("p"));
model.add(modelFactory.createText("password"));
model.add(modelFactory.createCloseElementTag("p"));
model.add(modelFactory.createStandaloneElementTag("input", "name", "password"));
// submit の input タグの作成
model.add(modelFactory.createStandaloneElementTag("input", "type", "submit"));
// form の終了タグの作成
model.add(modelFactory.createCloseElementTag("form"));

新しいタグ生成してみる(その他)

上で紹介していない IModelFactory のタグ生成メソッド。
あまり使う機会はないかも。。

そのほかの生成メソッド
メソッド 生成するもの
createComment コメントを生成
createCDATASection CDATASectionを作成
createHTML5DocType HTML5 の DocType を作成

とりあえずサンプルとして書き出してみるとこんな感じ。

model.add(modelFactory.createHTML5DocType());
model.add(modelFactory.createCDATASection("しーでーたー"));
model.add(modelFactory.createComment("コメントはさんどく?"));

レンダリング結果は次。

<!doctype html>
<!--[CDATA[しーでーたー]]-->
<!--コメントはさんどく?-->

新しいタグの属性値を編集してみる

上のログインフォームの生成例だと、いくつかのタグで属性値が付属しているので実際にログインフォームとして機能はできないはず(サンプルなのでご勘弁を。。)。
しっかりしたフォームを作ろうと思うとよりたくさんの属性値を追加する必要があり、そのためのメソッドも IModelFactory に用意されている。

新しいタグの属性値編集メソッド
メソッド 生成するもの
setAttribute 属性値を追加
removeAttribute 属性値を削除

例として、

<input type="text" name="username">

をそれぞれのメソッドを使いながら遠回しに作ってみると

IStandaloneElementTag inputTag = modelFactory.createStandaloneElementTag("input");
inputTag = modelFactory.setAttribute(inputTag, "type", "text");
inputTag = modelFactory.setAttribute(inputTag, "name", "username");
iinputTag = modelFactory.setAttribute(inputTag, "dummy", "dummyValue"); // お試しで追加してみたが、、
inputTag = modelFactory.removeAttribute(inputTag, "dummy");            // ダミー属性なんてやっぱりいらない。。
model.add(inputTag);

正直、この属性値の追加の仕方は個人的には好きではない。。
上のログインフォーム生成例のコードだと、生成 html と java コードの各行がちょうど対応関係があってみやすかったのに、属性値編集のメソッドで丸つぶれになってしまうため。

これを避けるために、createOpenElementTag または createStandaloneElementTag メソッドに属性値の組み合わせを Map で渡す方法もある。
こちらの方がまだマシかも。

// 属性値を Map で準備
HashMap<String, String> attributeMap = new HashMap<>();
attributeMap.put("type", "text");
attributeMap.put("name", "username");
// input タグの生成
model.add(modelFactory.createStandaloneElementTag("input", attributeMap, AttributeValueQuotes.DOUBLE, false, false));

新しく作ったタグを追加または置換してみる

作ったタグを実際に置換するための処理は IElementTagStructureHandler を使う。
主なメソッドは以下。

新しく作ったタグを追加または置換するメソッド
メソッド 実行内容
setBody 元タグの子要素にテキストを追加
insertBefore 元タグの直前に新しいタグを追加
insertImmediatelyAfter 元タグの直後に新しいタグを追加
replaceWith 元タグを新しいタグに置換

それぞれの使用例を書いてみる。
元のオリジナルタグを、

<ex:test>
  <p>hello</p>
</ex:test>

として、それぞれのメソッドの実行例を見てみる。

setBody

指定できるのは model か文字列。
元々のタグの中身を指定したものに変更してくれる。

model.add(modelFactory.createStandaloneElementTag("input", "type", "text"));
structureHandler.setBody(model, false);

レンダリング結果。

<ex:test>
  <input type="text">
</ex:test>

insertBefore

元々のタグの直前に新しいタグを追加してくれる。

model.add(modelFactory.createStandaloneElementTag("input", "type", "text"));
structureHandler.insertBefore(model);

レンダリング結果。

<input type="text">
<ex:test>
  <p>hello</p>
</ex:test>

insertImmediatelyAfter

元々のタグの直後に新しいタグを追加してくれる。
注意なのがあくまで指定したタグの直後ということなので、開始タグの直後に割り込む形になる。

model.add(modelFactory.createStandaloneElementTag("input", "type", "text"));
structureHandler.insertImmediatelyAfter(model, false);

レンダリング結果。

<ex:test>
  <input type="text">
  <p>hello</p>
</ex:test>

replaceWith

元々のタグを新しいタグに置換する。

model.add(modelFactory.createStandaloneElementTag("input", "type", "text"));
structureHandler.replaceWith(model, false);

レンダリング結果。

<input type="text">

元タグの属性値編集してみる

新しいタグを追加することなく、元タグの属性値のみを変更する時は IElementTagStructureHandler を使用する。

元タグの属性値編集メソッド
メソッド 実行内容
setAttribute 元タグに新しい属性値を追加
removeAttribute 元タグの属性値を削除

以下にサンプルコードを示す。
次のようなオリジナルタグを用意し、

<ex:test name="おなまえ"></ex:test>

それぞれのメソッドを使ってみると、

structureHandler.setAttribute("test", "testValue");
structureHandler.removeAttribute("name");

test 属性を追加し name 属性を追加したので、レンダリング結果は次。

<ex:test test="testValue"></ex:test>