Code Tips‎ > ‎

JavaScriptでヒアドキュメント

いくつかの言語ではヒアドキュメント機能が用意されていますが、JavaScriptには用意されていません。しかしJavaScriptでも工夫次第で似た機能を実現できます。このページでは、JavaScriptのヒアドキュメントの代替方法をいくつか取り上げます。


1:TEXTAREA要素を使う

<textarea id="text" style="display:none">
1<a href="…">…</a>
2<textarea>&lt;/textarea>
3<script src="…"></script>
</textarea>

<script>
var text = document.getElementById("text").innerText;
alert(text);
</script>

非表示にしたTEXTAREA要素にテキストを記述し、その要素の中身を丸ごと取得する方法です。導入は容易で記述できない文字列の少ない良案だと思います。

この方法には以下のデメリットがあります。
  • ヒアドキュメントを1つ追加するたびに、要素を1つ追加する必要がある
  • 値の取得の際に、特定の要素を指定する必要がある
  • TEXTAREAの閉じタグ「</textarea>」は「&lt;/textarea>」とする必要がある

2:リテラルを改行し、行末に「\」をつける。

var text = "\
1<a href=\"…\">…</a>\n\
2<textarea></textarea>\n\
3<script src=\"…\"><\/script>\n\
";
alert(text);

文字列リテラルを定義する部分で改行をいれて記述し、行末に「\」をつける方法です。要素の追加は必要ないものの「\」エスケープが多くなり見難くなると思います。

この方法には以下のデメリットがあります。
  • すべての行末に「\」をつける必要がある
  • 改行は無視されるので、さらに「\n」を明示的につける必要がある
  • 「"」は「\"」とする必要がある
  • SCRIPTの閉じタグ「</script>」は「<\/script>」とする必要がある
  • 全体的に見難くなる

3:別ファイルの内容を、そのまま変数に代入する:ActiveXObjectを使う方法

var fso = new ActiveXObject("Scripting.FileSystemObject");
var fso.OpenTextFile(filePath);
var text = inFile.ReadAll();

// 1行で書くと
var text = (new ActiveXObject("Scripting.FileSystemObject")).OpenTextFile(filePath).ReadAll();

ActiveXObjectのFileSystemObjectを利用して、別ファイルの中身をそのまま変数に代入する方法です。エスケープは必要なく、記述できない文字列が存在しないという点が魅力です。

この方法には以下のデメリットがあります。
  • 目的の文字列を別ファイルに記述する必要があるため、そもそも「ヒアドキュメント」ではない
  • ローカルで使用する場合にしか使えない
  • IEでしか使えない
※HTAなどで使用する場合には有効だと思います。

4:別ファイルの内容を、そのまま変数に代入する:Ajaxを使う方法

Ajaxで普通にアクセスし、変数に代入する方法です。※Ajaxのごくありふれたコードを書くだけなので、このページではコードはわざわざ書きません(内容の割に長いので)。Ajaxが分からない方は、申し訳ありませんが他のサイトを参照してください。

ActiveXObjectを使う方法と同じで、エスケープは必要なく、記述できない文字列が存在しないという点が魅力です。

この方法には以下のデメリットがあります。
  • 目的の文字列を別ファイルに記述する必要があるため、そもそも「ヒアドキュメント」ではない
  • 別ファイルをサーバに置く必要がある
  • HTTPアクセスが発生する
  • やりたいことの割には大掛かり

5:E4Xを使う(ECMAScript for XML)

E4Xは、ネイティブ XML サポートを JavaScript に追加するプログラミング言語拡張で、XML文書を簡易に扱う為の機能です。ECMA-357で2005年12月に標準化されています。

var text = <>
1&amp;lt;a href="…">…&amp;lt;/a>
2&amp;lt;textarea>&amp;lt;/textarea>
3&amp;lt;script src="…">&amp;lt;/script>
</>;
alert(text);

alert(<EOT>
1&amp;lt;a href="…">…&amp;lt;/a>
2&amp;lt;textarea>&amp;lt;/textarea>
3&amp;lt;script src="…">&amp;lt;/script>
</EOT>);

この方法には以下のデメリットがあります。
  • 現在(2011年12月)この機能を実装しているのはFireFoxのみ
  • タグは全般的にエスケープする必要がある

scriptタグ内にそれっぽく書く方法

上記で紹介した方法の他に、scriptタグ内の無視される個所やコメント部分に文字列を記述し、その文字列を取得して無駄な部分を省いて目的の文字列を得る方法があります。

ネット上を検索するといろいろな方法が提案されていることが分かります、どの方法も根本的な仕組みは共通しています。その中からいくつか紹介します。

6:JavaScriptでヒアドキュメントや簡易テンプレート - latest log


他の言語でサポートされているヒアドキュメント形式と似た雰囲気で利用できる為、なじみやすいと思います。

簡単に説明すると、script要素内に記述した文字列を「document.getElementById("…").text」で取得し、余計な部分を削除するという仕組みになります。

この方法には以下のデメリットがあります。
  • ヒアドキュメントを1つ追加するたびに、要素を1つ追加する必要がある
  • 値の取得の際に、特定の要素を指定する必要がある
  • script要素を「type="text/html"」とし無効化する必要がある
  • 独自ライブラリを参照する必要がある
  • 値を取得する際に、このライブラリ独自の形式を意識したクラス呼び出しをする必要がある
  • SCRIPTの閉じタグを記述することは不可能(?)

7:JavaScriptでヒアドキュメントを使うライブラリを作った。 - こせきの技術日記


こちらで紹介されている方法は、script要素内に記述した文字列をinnerHTMLで取得し加工しています。6の方法と似ていますがこちらは高度に隠蔽されていて、ライブラリを意識したコードにする必要がありません。

例えば、
  • 文字列の取得と変数への代入が自動的に行なえる
  • ヒアドキュメントを書いたscript要素の指定は不要
  • 1つのscript要素に複数のヒアドキュメントを書ける
などが挙げられます。

ですが、この方法にもデメリットがあります。
  • 独自ライブラリを参照する必要がある
  • 「"」を使うならprototype.jsを参照する必要がある
  • 「グローバルにアクセスできる変数やプロパティ」にしか代入できない

8:ヒアドキュメント、IE専用、コメント - oct inaodu

お手軽です。

この方法には以下のデメリットがあります。
  • IE専用
  • SCRIPTの閉じタグを記述することは不可能(?)

まとめ

ここまでで紹介した方法を簡単に表にまとめました。
方法 TEXTAREAの
閉じタグ
SCRIPTの
閉じタグ
その他のタグ ブラウザ依存 環境依存 ライブラリ
の参照
1:非表示TEXTAREA
2:行末に「\」
3:ActiveXObject ×(IEのみ) ×
4:Ajax ×
5:E4X ×(FireFoxのみ)
6:「latest log」さんの方法 × ×
7:「こせきの技術日記」さんの方法 ×
8:「oct inaodu」さんの方法 × ×
※タグの記述に関してはエスケープが必要なものは△、記述できないものを×とした。タグ以外の項目では、ブラウザ依存・環境依存・ライブラリの参照があれば×とした。

冒頭にも書きましたが、JavaScriptにはヒアドキュメントの機能が用意されていません。それを無理やり実現しようとしているので、どの方法でも何かしらのデメリットが出てくるのはやむを得ないと思います。多くの方法でそのまま記述できない文字列があることが印象的でした。

総合的に考えると、非表示のTEXTAREA要素に書くという方法が、もっとも分かりやすくシンプルで簡易に実現できるベターな案ではないかと思います。私はこの方法をよく使っています。

「もっとヒアドキュメントっぽく書きたい」という人は、「こせきの技術日記」さんが紹介されている方法を使ってみるのもいいと思います。※こちらはいろいろ工夫されており勉強になるので一読されてみるのもいいと思います。

FireFox限定でもいいのならE4Xはいい案だと思います。IE限定でいいのならActiveXObjectを使うのもいいと思います。


2012/01/08