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

ThymeleafでSmartyのnl2br的なことをするときにはまった(改行コード\nの置換)

JJUGのLT祭りで発表した「Thymeleafでハマったこと」の内容。
Springと連携して利用したThymeleafのテンプレート中で、Smartyのnl2br的なことをやろうと思ったときにハマった。

結果を先に書くと、上記の方法はあきらめて、ロジック側で\nでsplitした配列をThymeleafに渡して、th:eachで出力して末尾に<br />を付けるという対応になった。


以下調査メモ。

itにはロジック側で\nを含む文字列が設定されている状態で、以下のようなテンプレートを表示させると、

<span th:text="${#strings.replace(it, '\n', '<br />')}">default text</span>

SAXParseExceptionが発生する。

org.xml.sax.SAXParseException; lineNumber: 15; columnNumber: 53; The value of attribute "th:text" associated with an element type "span" must not contain the '<' character.
	org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)

<br />の部分で怒られている。
これを解決するだけなら、ThymeleafのtemplateModeを"LEGACYHTML5"にして(この場合、依存性にneko-htmlが必要なことに注意)、th:utext(エスケープしない)にして表示させると、エラーにならずに表示させることが出来る。
しかし、it内に入っているものもエスケープされないので注意。


はまったのはここから。
ここで、<br />をLFとかの普通の文字にして、先のエラーを回避したとしても一向に\nが置換されない。マニュアルを見ると、ThymeleafはSpring連携の際にOGNLの代わりにSpringELを利用しているらしく、こいつが\をエスケープしている模様。
デバッガで止めてみた結果が以下。beforeが\nのところで、見事にエスケープされている。

Spring連携しないで使うと以下のようにエスケープされていない。

SpringELでこの辺の設定変えられたりするのだろうか?SpringELについて調べる必要がありそう。