CLOVER🍀

That was when it all began.

Mustache.javaのテンプレートのデリミタを切り替える

ちょっとMustache.javaで、テンプレートのデリミタを変更できないか見ていまして。

Mustache.java
https://github.com/spullara/mustache.java

通常、Mustacheでは以下のように「{{」と「}}」をデリミタにしてテンプレートを書きますが、

{{name}}

これを変更したい、と。

Mustache.javaではありませんが、調べたらJavaScript版のMustacheについての内容が出てきたので、軽く動作確認してみます。

javascript - How to change the default delimiter of mustache.js? - Stack Overflow

準備

まずは、Maven依存関係。

        <dependency>
          <groupId>com.github.spullara.mustache.java</groupId>
          <artifactId>compiler</artifactId>
          <version>0.9.1</version>
        </dependency>

現時点の最新版は、0.9.1ですと。

その他、テストコード用にJUnitとAssertJを追加。

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.1.0</version>
            <scope>test</scope>
        </dependency>

あとは、淡々とコードを書いていきます。

動作確認

まずは、普通に使ってみるところから。

以降では、以下のimport文が定義済みとします。

import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

テンプレートをStringで定義して、普通に使ってみたバージョン。

    @Test
    public void testSimpleUsage() {
        String template = "{{name}}";

        Map<String, Object> scope = new HashMap<>();
        scope.put("name", "磯野 カツオ");

        MustacheFactory mf = new DefaultMustacheFactory();
        Mustache mustache = mf.compile(new StringReader(template), "example");

        StringWriter writer = new StringWriter();
        mustache.execute(writer, scope);
        writer.flush();

        assertThat(writer.toString())
                .isEqualTo("磯野 カツオ");
    }

これはまあ、いいでしょう。

続いて、デリミタを変更したバージョン。

    @Test
    public void testChangeDelimiter() {
        String template = "{{=<% %>=}}<%name%><%={{ }}=%>";

        Map<String, Object> scope = new HashMap<>();
        scope.put("name", "磯野 カツオ");

        MustacheFactory mf = new DefaultMustacheFactory();
        Mustache mustache = mf.compile(new StringReader(template), "example");

        StringWriter writer = new StringWriter();
        mustache.execute(writer, scope);
        writer.flush();

        assertThat(writer.toString())
                .isEqualTo("磯野 カツオ");
    }

というわけで、どうやら「これまでのデリミタ(開始)」「新しいデリミタ(開始)」「新しいデリミタ(終了)」「これまでのデリミタ(終了)」の順番で続ければよいみたいです。

また、もう1度書くことで再度デリミタを変更できるようです。

この例の場合は、「{{」と「}}」から「<%」と「%>」に変更し、最後に「{{」と「}}」に戻しています。

{{=<% %>=}}<%name%><%={{ }}=%>

なるほど。

最後は、テンプレートをファイルで用意。

src/test/resources/template.mustache

{{=<% %>=}}
<%name%>
<%! ここは、コメントです %>
<%={{ }}=%>
{{name}}

{{! ここは、コメントです }}

テストコード。

    @Test
    public void testChangeDelimiterUsingTemplateFile() {
        Map<String, Object> scope = new HashMap<>();
        scope.put("name", "磯野 カツオ");

        MustacheFactory mf = new DefaultMustacheFactory();
        Mustache mustache = mf.compile("template.mustache");

        StringWriter writer = new StringWriter();
        mustache.execute(writer, scope);
        writer.flush();

        assertThat(writer.toString())
                .isEqualTo("\n" +
                        "磯野 カツオ\n" +
                        "\n" +
                        "\n" +
                        "磯野 カツオ\n" +
                        "\n" +
                        "\n");
    }

コメントに使うデリミタも含めて、変更可能ですね、と。

HTMLエスケープを解除するには?

Mustacheではテンプレートに適用する値は、デフォルトでHTMLエスケープされます。

HTMLエスケープを解除するには、通常のデリミタを使用しているとこんな感じでしたが、

{{{message}}}
{{& message}}

デリミタを変更するとどうなるんだろう?ということで。

テストコード。

    @Test
    public void testHtmlEscaped() {
        Map<String, Object> scope = new HashMap<>();
        scope.put("value", "<HTML>");

        MustacheFactory mf = new DefaultMustacheFactory();
        Mustache mustache = mf.compile("template_html.mustache");

        StringWriter writer = new StringWriter();
        mustache.execute(writer, scope);
        writer.flush();

        assertThat(writer.toString())
                .isEqualTo("\n" +
                        "&lt;HTML&gt;\n" +
                        "<HTML>\n" +
                        "<HTML>\n");
    }

で、これをパスするためのテンプレートは、以下となります。もちろん、デリミタの変更を含みます。
src/test/resources/template_html.mustache

{{=<% %>=}}
<%value%>
<%{value}%>
<%& value%>

真ん中のパターンだと、「{」と「}」で囲まないといけないんですね。
※最初のパターンは、HTMLエスケープされる通常のパターンです