HOWTO · JavaScript
JavaScript を使用して HTML エンティティをデコードする
この記事では、JavaScript を使用して HTML エンティティをデコードする方法を説明します。
このページの内容
文字列内の HTML エンティティをデコードするには、ブラウザーで動作するコードならブラウザーの textarea 要素を、Node.js プロジェクトなら he パッケージを使います。どちらの方法でも、 、'、& などの文字参照を対応する文字に変換できます。入力例にはリテラルの <h2> タグと <br> タグも含まれていますが、エンティティをデコードしてもこれらのタグは削除されません。
Vanilla JavaScript で HTML エンティティをデコードする
ブラウザーの textarea を使うと文字参照をデコードできますが、innerHTML セッターは HTML 構文を解析します。信頼できない入力を割り当てる前に、リテラルの小なり記号をエスケープしてください。そうすれば、</textarea><img src=x onerror=alert(1)> のような文字列で解析コンテキストを閉じたり、要素を作成したりできません。文字参照は引き続きデコードされ、リテラルのタグ文字列はテキストとして残ります。この方法には document が必要なため、Node.js で直接ではなくブラウザーで実行します。
以下は、ブラウザーで動作する完全なページの例です。サンプル文字列をデコードしたい値に置き換えてください。この関数は解析前にリテラルの < をエスケープし、ページでは返された値を textContent で表示します。
<!doctype html>
<meta charset="utf-8">
<textarea id="source"></textarea>
<pre id="result"></pre>
<script>
function decodeEntities(input) {
const textarea = document.createElement('textarea');
textarea.innerHTML = input.replace(/</g, '<');
return textarea.value;
}
const input = "Give us some'<h2>time</h2>' & space <br> Please";
document.querySelector('#source').value = input;
document.querySelector('#result').textContent = decodeEntities(input);
</script>
リテラルの < を1つずつエスケープすると、入力によって textarea の終了タグやほかの要素のマークアップが解析器に渡されるのを防げます。< のようなエンコード済みの文字参照はデコードされますが、結果の < は textarea の値の中でテキストとして扱われ、マークアップとして再解析されることはありません。textContent への代入でも、デコードされた <h2> と <br> はテキストとして表示されます。デコードしたデータを後で HTML として描画する場合は、その描画処理の段階で適切な HTML サニタイズ方針を適用してください。
セミコロンで終わる10進数の数値文字参照を扱う簡単な Node.js の例では、String.fromCodePoint() を使って、JavaScript が受け付ける一致値を変換できます。このヘルパーは HTML の数値文字参照の規則を適用しません。� は U+0000 に、� は単独サロゲート U+D800 になりますが、HTML パーサーではどちらも U+FFFD に置き換えられます。また、不正な形式や範囲外の参照も検証しません。範囲外の値を渡すと String.fromCodePoint() が RangeError を投げることがあります。セミコロンのない参照はそのまま残ります。これは限定的な例で、完全な HTML エンティティデコーダーではありません。より幅広いエンティティ構文を扱う場合は、上記のブラウザー方式か、以下の he パッケージを使ってください。
この例を実行します。
function decodeDecimalReferences(input) {
return input.replace(/&#(\d+);/g, (_, digits) =>
String.fromCodePoint(Number(digits))
);
}
console.log(decodeDecimalReferences("Give' us time"));
Give' us time
he ライブラリで HTML エンティティをデコードする
Node.js では、npm install he で he パッケージをインストールし、const he = require('he'); で読み込んでから、he.decode(input) で文字列をデコードします。he は名前付きおよび数値形式の HTML 文字参照に対応しているため、さまざまなエンティティを含む入力には、手書きの置換リストより適しています。すべてのバージョンに対応すると決めつけず、パッケージが現在要求する Node.js のエンジン条件をプロジェクトの Node.js バージョンと照らし合わせてください。
decode() 関数では、HTML 文字列を第1引数として指定する必要があります。省略可能な第2引数はオプションオブジェクトです。isAttributeValue や strict などのプロパティは、そのオブジェクトに設定する真偽値であり、個別の値として直接渡すものではありません。通常のテキストなら、オプションを付けずに he.decode(input) を呼び出します。上記の入力例を使うと、デコード後の文字列は Give us some'<h2>time</h2>' & space <br> Please になります(Give の後の空白はノーブレークスペースです)。
すでにブラウザーで動作しているコードには textarea を、Node.js や幅広いエンティティに対応する単独のデコーダーが必要な場合には he を選びます。デコードで変換されるのは文字参照であり、サンプル内のリテラルなタグは削除されません。デコードと安全な描画は別の処理として扱ってください。