DOM

【JavaScript】htmlタグのエスケープ処理はちょっと難しいので整理してみる

更新日:2023/03/30

JavaScriptでユーザー入力やWebAPI等から取得した文字をそのままブラウザで表示すると、リンクやスクリプト等のタグが紛れ込んで意図しない結果を招く可能性があります。
そのためタグを無害化するエスケープ処理を行うのですが、場合によってはそのまま表示できます。
少し混乱ぎみなので、整理してみます。

 

表示するだけならエスケープ無用

他の文字と組み合わせてもよいが、そのままブラウザで表示するならエスケープしなくても大丈夫です。

例えば次のようなタグに文字を挿入します。

<p id="p1"></p>

innerTextに代入すると、タグもそのまま表示されます。

const input = '<a href="http://xxx.com">xxx</a>';
document.getElementById("p1").innerText = `今日は${input}ですね`;

タグ文字がそのまま表示された

innerHTMLを使うとタグが有効になります。

const input = '<a href="http://xxx.com">xxx</a>';
document.getElementById("p1").innerHTML = `今日は${input}ですね`;

タグが有効になった

pタグなどに文字列そのまま挿入するときは、innerTextを使いましょう。

 

spanタグ等と組み合わせる

spanタグなどで文字を装飾したいなど、htmlタグと入力値を組み合わせたいときは少し難しいです。

正攻法

正攻法はappendChild()で順番に要素を追加していきます。

const input = '<a href="http://xxx.com">xxx</a>';
const p1 = document.getElementById("p1");
p1.appendChild(document.createTextNode("今日は"));

const span = document.createElement("span");
span.style.color = "red";
span.innerText = input;
p1.appendChild(span);

p1.appendChild(document.createTextNode("です"));

面倒ですね!

htmlエスケープする関数

そこで、入力値をエスケープします。

const escape_html = s => s.replace(/[&'"<>]/g, m=>({
      "&": "&amp;",
      "'": "&apos;",
      '"': '&quot;',
      '<': '&lt;',
      '>': '&gt;',
})[m] );

対象の文字列を置換しているだけです。

上の関数を使って入力値をエスケープして、タグを含んだ文字に連結します。
そしてinnerHTMLにセットします。

const input = '<a href="http://xxx.com">xxx</a>';
document.getElementById("p1").innerHTML
        = `今日は<span style="color:red">${ escape_html(input) }<span>です`;

エスケープした入力値を装飾して表示

入力値を装飾して表示できました。

htmlエスケープする関数:改良版

前述の関数は文字列以外の値を使うとエラーになります。
ブラウザでの入力は基本的に文字列なので問題ないのですが、使い方によっては想定外の値が紛れ込むケースもあります。

そのようなケースを想定して、関数を改良してみます。

const escape_html = s => typeof s !== "string" 
        ? escape_html( s.toString() ) 
        : s.replace(/[&'"<>]/g, m=>({
            "&": "&amp;",
            "'": "&apos;",
            '"': '&quot;',
            '<': '&lt;',
            '>': '&gt;',
        })[m] );

typeofで文字列かどうかを確認して、文字列でなかったらtoString()で文字化してescape_html()を呼び出しています。

エスケープ結果をいくつかのパターンで確認してみます。

console.log( escape_html( 123 ) ); // 123
console.log( escape_html( [1,2,3] ) ); // 1,2,3
console.log( escape_html( true ) ); // true
console.log( escape_html( {a:1,b:2} ) ); // [object Object]

[object Object]なんてイヤ!
というときは、値の型をチェックして文字列を返すような関数を作成してみてください。

更新日:2023/03/30

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。