エスケープ処理しつつ改行をbrタグにしてhtmlに出力したい

エスケープ処理しつつ改行をbrタグにしてhtmlに出力したい

こんにちは。kkです。

タイトル通りですが、例えばこんな場面を想定します。

・表示するデータをどこかから取得
・改行が含まれている
・XSS対策でエスケープ処理を行う

jstlのc:outだと、エスケープと同時に出力するので改行をbrに置換できず、先に置換するとエスケープされてしまいます。
サーバ側でエスケープ処理を行い、改行をbrタグに置換した上で画面へ渡す場合、画面側がサーバの処理を意識する必要があります。(c:out等で出力すると結局brタグもエスケープされる)
fn:splitで改行毎に分割し、個々にc:outしつつbrを入れていく…というのも考えられますが、下記のような問題(仕様)もありちょっとかっこ悪いです。
[Java]JSTLで改行でのsplit()ができない問題 そこで、jstlのc:outのような感覚で、簡易に使えるカスタムタグがあると便利かなーと思い、作成してみました。 処理内容についてはコード内のコメントを参照してください。 ここでは、jstlライブラリ内のOutSupportを使用しています。

  • NewLineToBRTag.java
  • NewLineToBRTag.tld
[java] package jp.co.opentone.tag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; import org.apache.taglibs.standard.tag.common.core.OutSupport; /** * 改行をbrタグにして出力する。 */ public class NewLineToBRTag extends TagSupport { // 対象文字列 必須 private String value; // エスケープ実施有無 非必須 private boolean escapeXml = true; /** * doStartTag */ @Override public int doStartTag() throws JspException { try { JspWriter writer = pageContext.getOut(); // 改行コードを全てLFに変換し、LFでsplit for (String str : value.replaceAll(“\r\n”, “\n”).replaceAll(“\r”, “\n”).split(“\n”)) { // OutSupport.outで出力(escapeXml=true でエスケープ) OutSupport.out(pageContext, escapeXml, str); // brタグを出力 writer.write(“<br />”); } } catch (IOException e) { throw new JspException(e.getMessage()); } return SKIP_BODY; } /** * doEndTag */ @Override public int doEndTag() throws JspException { return EVAL_PAGE; } /** * valueを設定します。 * @param value value */ public void setValue(String value) { this.value = value; } /** * escapeXmlを設定します。 * @param escapeXml escapeXml */ public void setEscapeXml(boolean escapeXml) { this.escapeXml = escapeXml; } } [/java]
[xml]
<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <tlib-version>1.0</tlib-version>
    <short-name>br</short-name>

    <tag>
        <name>newLineToBr</name>
        <tag-class>jp.co.opentone.tag.NewLineToBRTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>value</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>escapeXml</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
</taglib>
[/xml]

使えるようにするため、web.xmlに追加します。

  • web.xml
[xml]
    <jsp-config>
        <taglib>
            <taglib-uri>http://opentone.co.jp/sample/tag/NewLineToBR</taglib-uri>
            <taglib-location>/WEB-INF/tags/NewLineToBRTag.tld</taglib-location>
        </taglib>
    </jsp-config>
[/xml]


さっそく画面表示して試してみます。

ちゃんと出来てますね。
テスト用に書いたコードはこちら。
※例によって、以前作成したSpringのサンプルプロジェクトの流用
 →SpringIDEで始めるSpringMVCプロジェクト

  • HomeController.java
[java]
@Controller
public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    private static final String CR = "\r";
    private static final String LF = "\n";
    private static final String CRLF = "\r\n";

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);

        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

        String formattedDate = dateFormat.format(date);

        // 改行を含む文字列の作成
        String value =
                "CR改行" + CR +
                "LF改行" + LF +
                "CRLF改行" + CRLF +
                "<i>最後の行</i>";

        model.addAttribute("serverTime", formattedDate );
        model.addAttribute("testNewLineValue", value );

        return "home";
    }
}
[/java]
  • home.jsp
[html]
<%@ page pageEncoding="UTF-8" %>
<%@ page session="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://opentone.co.jp/sample/tag/NewLineToBR" prefix="br" %>
<html>
<head>
    <title>Home</title>
</head>
<body>
<h1>
    Hello world!
</h1>

<P>  The time on the server is ${serverTime}. </P>
<h2>【改行を含む文字列表示】</h2>
<P> ${testNewLineValue} </P>

<h2>【br変換テスト】</h2>
<P><br:newLineToBr value="${testNewLineValue}"/></P>

</body>
</html>
[/html]


1行ですっきり書けました。(名前長いけど…)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です