XPagesでJavaScriptに文字列を渡すと文字化け… toJson() で解決した理由

XPagesで文字化け? toJson() を使ったらうまくいった話

XPagesでサーバーサイドの文字列をクライアントサイドJavaScriptへ渡す際、
文字列の内容によってはJavaScriptが正しく動作しなくなることがあります。

特に、以下のような文字が含まれている場合は注意が必要です。

  • ダブルクォート "
  • シングルクォート '
  • バックスラッシュ \
  • 改行
  • タブ
  • 日本語などのUnicode文字

今回、XPagesで文字列をJavaScriptへ渡す処理を見直したところ、
toJson() を使用することで安全に受け渡せることが分かりました。

もともとの処理

例えば、SSJS側に以下のような関数があるとします。

function getSampleText() {
    return "商品名:テスト商品";
}

この値をクライアントサイドJavaScriptへ渡したい場合、
単純に以下のように記述したくなります。

#{javascript:getSampleText()}

文字列が単純な内容であれば、問題なく動作する場合もあります。

しかし、実際のデータでは文字列内に改行やダブルクォートなどが含まれることがあります。

例えば以下のような文字列です。

商品名:テスト商品
備考:"特価品"

この文字列をそのままJavaScriptへ埋め込もうとすると、
生成されるJavaScriptが正しい構文にならない可能性があります。

なぜ問題が発生するのか

JavaScriptで文字列を扱う場合、文字列は通常以下のように記述します。

var text = "テスト";

しかし、文字列自体にダブルクォートが含まれていると、
例えば以下のような状態になる可能性があります。

var text = "備考:"特価品"";

これでは、JavaScriptがどこまでを文字列として扱えばよいのか判断できません。
そのため、JavaScriptエラーの原因になります。

また、改行やバックスラッシュなども、
そのままJavaScriptソースへ埋め込むと問題になる場合があります。

つまり、
サーバー側では正常な文字列でも、JavaScriptのソースコードとして直接埋め込むと壊れることがある
ということです。

toJson() を使う

そこで使用できるのがXPagesの toJson() です。

今回の記述は以下です。

#{javascript:toJson(getSampleText())};

getSampleText() が返した文字列を、
toJson() に渡しています。

例えば元の文字列が、

商品名:テスト商品
備考:"特価品"

だった場合、JavaScriptへ渡す際には概念的に以下のような形式になります。

"商品名:テスト商品\n備考:\"特価品\""

ダブルクォートは \"
改行は \n のように、
JavaScriptやJSONで安全に扱える形式へエスケープされます。

その結果、ブラウザ側では例えば以下のような正常なJavaScriptとして扱うことができます。

var sampleText = "商品名:テスト商品\n備考:\"特価品\"";

JavaScriptが実際に値を取得すると、中身は元通りです。

商品名:テスト商品
備考:"特価品"

処理の流れ

getSampleText()
      ↓
サーバー側では正常な文字列

商品名:テスト商品
備考:"特価品"

      ↓
   toJson()

"商品名:テスト商品\n備考:\"特価品\""

      ↓
ブラウザへ出力

      ↓
JavaScriptが安全に解釈

      ↓
元の文字列として利用できる

つまり toJson() は、簡単に言うと、

「この文字列をJavaScriptに渡してもぶっ壊れない形にするマン」

と考えると分かりやすいです。

toJson() は文字化けを直す処理ではない

ここは注意が必要です。

toJson() を使用した結果、日本語の表示が正常になり、
toJson() で文字化けが直った」
ように見える場合があります。

しかし、厳密には toJson() は文字コード変換を行うための関数ではありません。

例えば getSampleText() の時点で、すでに以下のように文字化けしている場合、

繧ケ繝医Μ繝ウ繧ー

以下のようにしても、元の日本語へ復元されるわけではありません。

toJson(getSampleText())

UTF-8やShift_JISなど、文字コードの不一致が原因の場合は、
ファイル読み込み処理やHTTPレスポンスなど、別の箇所を確認する必要があります。

今回うまくいった理由

今回の場合、
getSampleText() で取得した段階では日本語は正常でした。

問題は、その文字列をXPagesからブラウザ側のJavaScriptへ渡す部分にありました。

そこで、

#{javascript:toJson(getSampleText())};

と変更したことで、以下のような処理が行われます。

  1. JavaScript用の文字列として扱える形になる
  2. ダブルクォートがエスケープされる
  3. 改行が \n のような形に変換される
  4. バックスラッシュなども適切に処理される
  5. JavaScript側で安全に文字列として解釈できる

その結果、見た目としては
「文字化けが直った」
ように見えた、ということになります。

例えばこんな文字列でも安全になる

例えば以下のようなデータがあるとします。

担当者:"田中"
保存先:C:\work\test
備考:
1行目
2行目

このような文字列をそのままJavaScriptへ渡すのは少し危険です。

toJson() を通すと、概念的には以下のようになります。

"担当者:\"田中\"\n保存先:C:\\work\\test\n備考:\n1行目\n2行目"

これならJavaScriptの文字列として安全に扱うことができます。

まとめ

XPagesのサーバーサイド処理で取得した文字列を、
クライアントサイドJavaScriptへ渡す場合は、

#{javascript:toJson(getSampleText())}

のように toJson() を使用すると安全です。

特に、外部ファイルやDBなどから取得した文字列には、
日本語、改行、ダブルクォート、バックスラッシュなどが含まれることがあります。

そのままJavaScriptへ埋め込むよりも、
toJson() を通したほうが安全に扱えます。

ただし、toJson() は文字化けを修復する関数ではありません。

役割としては、


サーバー側の文字列を、JavaScript側で安全に解釈できるJSON形式の文字列へ変換する

という理解が分かりやすいと思います。

XPagesで
「サーバー側では正常なのにJavaScriptへ渡すとうまく表示されない」
「クォートや改行が入るとJavaScriptエラーになる」
といった場合には、toJson() を試してみる価値があります。