none
JSON のスラッシュ「/」の扱いの仕様と出力結果の相違について RRS feed

  • 質問

  • いつもお世話になっております、おのでらです。


     今回は技術的な質問というよりは方針についてお聞きしたいと思っております。私の解釈が間違っているかもしれませんがその時はご指摘ください。


     現在 ASP.NET MVC で JSON を返すシステムを作成しているのですが、JSON のフォーマットについて気になっているところがあり「スラッシュ(/)」をエスケープするのかしないのかというところで確信が持てないところでいます。

     ASP.NET MVC の「Controller.Json」メソッドが返すフォーマットのスラッシュはエスケープされずにテキストを返します。(DateTimeのスラッシュは除きます。)
     返された JSON フォーマットをクライアント側で「DataContractJsonSerializer」クラスを使用してデシリアライズをかけてクラスのインスタンス化を行おうと思っているのですが、DataContractJsonSerializer クラスが扱う JSON フォーマットはスラッシュをエスケープして処理します。

     そのため、ASP.NET MVC のサービスから受けとった JSON テキストをクライアントの DataContractJsonSerializer でそのままデシリアライズを行うと Root 要素が見つからないというエラーが発生してしまい正常にデシリアライズできません。デシリアライズを行うには受け取ったテキストから「/」を「\/」に変換する必要があります。(Dateのスラッシュを間違ってエスケープしないように注意)


     そこで JSON の仕様を確認すべく「RFC 4627」の確認を行ったのですが、「2.5.  Strings」の項目には「/(solidus)」はエスケープ対象となっていました。しかし、その先にある「8. Examples」ではなせか「Url」のパラメータにあるスラッシュはエスケープされておりません。(URI は例外なのかと思いましたがはっきりしていません)


     ためしに各種 Web サービスが提供している API から JSON の出力結果を引っ張ってきて確認してみました。ほかのサービスは RFC に則っているのかと思いきや下記のようにバラバラでした。

    【スラッシュをエスケープする Web API サービス】
    ・del.icio.us
    ・Yahoo! (U.S.)

    【スラッシュをエスケープしない Web API サービス】
    ・Twitter
    ・ECナビ
    ・Google
    ・livedoor Clips
    ・Wassr
    ・はてなハイク

    【なぜかエスケープありなしが混在してわけがわからない Web API サービス】
    ・Flickr

     

    【質問内容】
    1.JSON のフォーマットでスラッシュ(/)はエスケープすべきなのかしないべきなのか。また例外があったりするのでしょうか?

    2.JSON と JSONP でも統一されていない感じがありますが、JSON と JSONP でスラッシュの扱いがことなったりすることがあるのでしょうか?


     個人的にはスラッシュはエスケープしなくても問題ないと思っているのですが、RFC で定義されている以上則った方がいいとも思うところもあり、反面エスケープしていないサービスの方が多いのでそちらに合わせるべきかと迷うところがあります。

     スラッシュをエスケープするのが正しいとなった場合「Controller.Json」メソッドは使用できないことになり、自前でシリアライズしなければいけなくなるので面倒かなあとも思ったりしています。(DataContractJsonSerializer でシリアライズして返せばいいじゃんというものありますが…)

    このあたりの情報で詳しい方がいれば回答お待ちしております。


    おのでら (http://sorceryforce.com/)

    2012年2月9日 4:03

回答

  • RFCを読んだ限りでは、 unescaped の範囲にも %x2F が含まれていますし、escape %x2F もあります。

    ということはエンコードする側は、 / でも \/ でも \u002F でもよく、デコードする側はこれらのいずれもを受け入れる必要があります。

    Root要素が見つからないというのは何か別のエラーじゃありませんか?

    2012年2月9日 5:58

すべての返信

  • RFCを読んだ限りでは、 unescaped の範囲にも %x2F が含まれていますし、escape %x2F もあります。

    ということはエンコードする側は、 / でも \/ でも \u002F でもよく、デコードする側はこれらのいずれもを受け入れる必要があります。

    Root要素が見つからないというのは何か別のエラーじゃありませんか?

    2012年2月9日 5:58
  • 佐祐理さん回答ありがとうございます。

    RFCを読んだ限りでは、 unescaped の範囲にも %x2F が含まれていますし、escape %x2F もあります。

    ということはエンコードする側は、 / でも \/ でも \u002F でもよく、デコードする側はこれらのいずれもを受け入れる必要があります。

    確認したところ確かに unescaped の範囲に%x2F が含まれておりました。escape のところを気にしていて unescaped のところを見落としていました…。

    Root要素が見つからないというのは何か別のエラーじゃありませんか?

    すみません、こちらも再確認したところ HttpWebRequest, HttpWebResponse を使用して非同期で JSON テキストのバッファを取得し MemoeyStream に格納していたのですが、書き込んだ MemoeyStream をそのまま DataContractJsonSerializer に渡しているのが原因でした。取得したバッファを新たな MemoeyStream に書き出して DataContractJsonSerializer に渡すことによって問題なく動作するようになりました。


    おのでら (http://sorceryforce.com/)

    2012年2月9日 9:13
  • JSON のもともとの要求は 『JavaScript (ECMA Script) として実行可能であること』です。それがデータ交換フォーマットとして規約化されていっているものです。

    '/' は unescape にも escape にも含まれていて、"/" と書いてもよいし "\/" と書いてもよいことになっています。これは、JavaScript のエスケープシーケンスの処理の都合ですので、そういうものです。

    Perl なんかだと、全ての文字がエスケープ可能で、特別な意味を持たない文字をエスケープした場合にその文字を表すような仕様ですが、JavaScript や C# では、特別な意味を持たない文字をエスケープすることが文法違反となるため、エスケープが可能な文字が制限されています。それに対して、エスケープが不要な文字は文法上で意味を持たないすべての文字となるため、このような仕様になっているのでしょう。


    2012年2月10日 4:13