web-dev-qa-db-ja.com

JSON構文はオブジェクト内の重複キーを許可しますか?

これは有効なjsonですか?

{
    "a" : "x",
    "a" : "y"
}

http://jsonlint.com/ yesと答えます。

http://www.json.org/ は、禁止されていることについて何も言っていません。

しかし、明らかにそれはあまり意味がありませんか?ほとんどの実装はおそらくハッシュテーブルを使用するため、とにかく上書きされます。

162
clamp

標準(p。ii) から:

他の標準では、これを参照し、JSONテキスト形式に厳密に準拠しながら、さまざまなエンコードの詳細に制限を課すことが予想されます。このような標準には、特定の動作が必要になる場合があります。 JSON自体は動作を指定しません。

標準(p。2)のさらに下のJSONオブジェクトの仕様:

オブジェクト構造は、0個以上の名前/値のペアを囲む中括弧のペアとして表されます。名前は文字列です。各名前の後に単一のコロントークンが続き、名前と値を区切ります。単一のコンマトークンは、値を次の名前から分離します。

Diagram for JSON Object

重複キーが無効または有効であることについては何も言及していないため、仕様によれば、それは許可されていることを意味します。

JSONライブラリのほとんどの実装が重複キーを受け入れないnotは、最初の引用のために標準と競合しません。

C++標準ライブラリに関連する2つの例を次に示します。いくつかのJSONオブジェクトをstd::mapにデシリアライズするとき、重複キーを拒否するのは理にかなっています。ただし、一部のJSONオブジェクトをstd::multimapに逆シリアル化する場合は、通常どおりに重複キーを受け入れるのが理にかなっています。

100
Timothy Shields

短い答え:はい、しかし推奨されません。
長い答え:有効と呼ぶものに依存します...


JSON Data Interchange Format(ECMA-404) は、重複した名前(キー)について何も言いません。

ただし、 The JavaScript Object Notation(JSON)Data Interchange Format)(RFC7159) のコメント:

オブジェクト内の名前は一意である必要があります。

このコンテキストでは、shouldRFC 2119 で指定されているように理解する必要があります

この言葉、または「推奨」という形容詞は、特定の状況で特定の項目を無視する正当な理由が存在する可能性があることを意味しますが、別のコースを選択する前に完全な意味を理解して慎重に検討する必要があります。



RFC 7159は、一意の名前(キー)が適切な理由を説明しています。

名前がすべて一意であるオブジェクトは、ある意味で相互運用可能です
そのオブジェクトを受け取るすべてのソフトウェア実装が名前と値のマッピングに同意すること。オブジェクト内の名前がそうでない場合
ユニーク、そのようなオブジェクトを受け取るソフトウェアの動作は
予測不可能な。多くの実装は、最後の名前/値のペアを報告します
のみ。他の実装はエラーを報告するか、解析に失敗します
オブジェクト、および一部の実装はすべての名前/値のペアを報告し、
重複を含む。

JSON解析ライブラリは、呼び出し元のソフトウェアからオブジェクトメンバーの順序を認識できるようにするかどうかが異なることが確認されています。動作がメンバーに依存しない実装
注文は相互運用可能ではないという意味で相互運用可能です
これらの違いの影響を受けます。




また、セルゲイがコメントで指摘したように、 ECMA-262 "ECMAScript®Language Specification"には次のように書かれています。

オブジェクト内に重複する名前文字列がある場合、同じキーの字句的に先行する値は上書きされます。

(つまり、last-value-wins)。




Douglas CrockfordによるJava実装 (JSONの作成者)を使用して重複した名前の文字列を解析しようとすると、例外が発生します。

org.json.JSONException: Duplicate key "status"  at
org.json.JSONObject.putOnce(JSONObject.Java:1076)
102
user454322

JSON形式を指定する2つのドキュメントがあります。

  1. http://json.org/
  2. https://tools.ietf.org/html/rfc7159

受け入れられた回答は、最初のドキュメントから引用しています。最初のドキュメントはより明確ですが、2番目のドキュメントには詳細が含まれていると思います。

2番目のドキュメントには次のように書かれています。

  1. オブジェクト

    オブジェクト構造は、0個以上の名前/値のペア(またはメンバー)を囲む中括弧のペアとして表されます。名前は文字列です。各名前の後に単一のコロンが続き、名前と値を区切ります。単一のコンマは、値を次の名前から分離します。 オブジェクト内の名前は一意である必要があります

したがって、重複した名前を使用することは禁止されていませんが、推奨されていません。

18
toongeorges

XMLとJSONの両方を受け入れるAPIを扱うときに同様の質問に出くわしましたが、JSONで重複キーになると予想されるものをどのように処理するかについては文書化していません。

以下は、サンプルJSONの有効なXML表現です。

<object>
  <a>x</a>
  <a>y</a>
</object>

これがJSONに変換されると、次のものが得られます。

{
  "object": {
    "a": [
      "x",
      "y"
    ]
  }
}

重複キーと呼ばれるものを別のキーに処理する言語からの自然なマッピングは、ここでの潜在的なベストプラクティスのリファレンスとして役立ちます。

それが誰かを助けることを願っています!

8
a darren

JSON仕様には次のように記載されています。

オブジェクトは、名前と値のペアの順序付けられていないセットです。

ここで重要な部分は「順不同」です。特定のペアを参照するために使用できるのはそのキーだけなので、キーの一意性を意味します。

さらに、ほとんどのJSONライブラリは、キーが一意であることが保証されているハッシュマップ/辞書にJSONオブジェクトをデシリアライズします。重複キーを持つJSONオブジェクトをデシリアライズするとどうなるかはライブラリによって異なります。ほとんどの場合、エラーが発生するか、重複キーの最後の値のみが考慮されます。

たとえば、Pythonでは、json.loads('{"a": 1, "a": 2}'){"a": 2}を返します。

6
Max Noel

一意である必要は、一意である必要があるという意味ではありません。ただし、前述のように、一部のパーサーは失敗し、他のパーサーは解析された最後の値を使用します。ただし、重複を許可するために仕様が少しクリーンアップされた場合、JSONをHTMLまたは他の形式に変換するイベントハンドラーがある可能性があります...そのような場合、それは完全に有効ですJSONを解析し、別のドキュメント形式を作成...

[
  "div":
  {
    "p":"hello",
    "p":"universe"
  }
  "div":
  {
    "h1":"Heading 1",
    "p":"another paragraph"
  }
]

その後、たとえば、簡単にhtmlに解析できます

<body>
 <div>
  <p>hello</p>
  <p>universe</p>
 </div>
 <div>
  <h1>Heading 1</h1>
  <p>another paragraph</p>
 </div>
</body>

私は質問の背後にある理由を見ることができますが、現状では...私はそれを信用しません。

3
Colin Saxton

目的を尋ねると、さまざまな答えがあります。

JSONを使用してオブジェクト(JavaScriptObjectNotation)をシリアル化すると、各ディクショナリ要素は個々のオブジェクトプロパティにマップされるため、同じプロパティの値を定義する異なるエントリは意味を持ちません。

しかし、非常に具体的なユースケースから同じ質問に出くわしました。APIテスト用のJSONサンプルを作成するとき、使いやすさを損なうことなくJSONファイルにコメントを追加する方法を考えていました。 JSON仕様はコメントを認識しないため、非常に単純なアプローチを思い付きました。

重複するキーを使用してJSONサンプルをコメントするには。例:

{ "property1" : "value1", "REMARK" : "... prop1 controls ...", "property2" : "value2", "REMARK" : "... value2 raises an exception ...", }

私たちが使用しているJSONシリアライザーは、これらの「REMARK」の複製には問題がなく、アプリケーションコードはこの小さなオーバーヘッドを無視します。

したがって、アプリケーション層に意味はありませんが、これらの重複は、JSONの使いやすさを損なうことなく、テストサンプルにコメントを追加するための貴重な回避策を提供します。

2
aknoepfel

インターネット技術特別調査委員会(IETF)によって公開されたJSONの現在の標準であるRFC-7159によると、「オブジェクト内の名前は一意である必要があります」と述べています。ただし、IETF文書で使用される用語を定義するRFC-2119によれば、「本来」という言葉は「...特定の状況を無視して特定の項目を無視する正当な理由があるかもしれませんが、完全な意味を理解し、別のコースを選択する前に慎重に計量しました。」これが本質的に意味することは、一意のキーを持つことをお勧めしますが、必須ではありません。 JSONオブジェクトに重複したキーを含めることができますが、それはまだ有効です。

実際のアプリケーションから、JSONで重複キーが見つかった場合、最後のキーの値が考慮されることを見てきました。

1
Navaneetha

ECMA JSON標準 では定義されていません。そして一般的に言えば、標準の定義の欠如は、「これがどこでも同じように機能することを期待しないでください」という意味です。

ギャンブラーの場合、「多くの」JSONエンジンは複製を許可し、最後に指定した値を使用します。この:

var o = {"a": 1, "b": 2, "a": 3}

これになります:

Object {a: 3, b: 2}

しかし、あなたがギャンブラーではない場合、それを頼りにしないでください!

1
svidgen

規格について多くの時代遅れのアイデアと混乱があるため、投稿と回答。 2017年12月現在、2つの競合する標準があります。

RFC 8259- https://tools.ietf.org/html/rfc8259

ECMA-404- http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf

json.orgはECMA-404がthe標準であると示唆していますが、このサイトは権威者ではないようです。ここで重要なのは、ECMAを権威と見なすことは公平だと思いますが、(一意のキーに関して)標準間の唯一の違いは、RFC 8259がキーshouldそして、ECMA-404は、それらが一意である必要はないと述べています。

RFC-8259:

「オブジェクト内の名前は一意である必要があります。」

そのようなすべての大文字で「すべき」という言葉は、RFCの世界内で意味を持ち、別の標準で明確に定義されています(BCP 14、RFC 2119- https://tools.ietf.org/html/rfc2119 )as、

  1. この言葉、または「推奨」という形容詞は、特定の状況で特定の項目を無視する正当な理由が存在する可能性があることを意味しますが、別のコースを選択する前に完全な意味を理解して慎重に検討する必要があります。

ECMA-404:

「JSON構文は、名前として使用される文字列に制限を課さず、名前文字列が一意であることを要求せず、名前/値のペアの順序に重要性を割り当てません。」

したがって、どのようにスライスしても構文的に有効なJSONです。

RFC 8259で一意のキーを推奨する理由は、

名前がすべて一意であるオブジェクトは、そのオブジェクトを受け取るすべてのソフトウェア実装が名前と値のマッピングに同意するという意味で相互運用可能です。オブジェクト内の名前が一意でない場合、そのようなオブジェクトを受け取るソフトウェアの動作は予測できません。多くの実装では、最後の名前/値のペアのみが報告されます。他の実装はエラーを報告するか、オブジェクトの解析に失敗し、一部の実装は重複を含むすべての名前/値のペアを報告します。

言い換えれば、RFC 8259の観点からは有効ですが、パーサーはバーフする可能性があり、値がそのキーとペアになるかどうかについての約束はありません。 ECMA-404の観点から(私は個人的に権威として考えます)、それは有効な期間です。これは、解析を拒否するパーサーが壊れていることを意味します。これらの標準の両方に従って少なくとも解析する必要があります。しかし、それがどのようにネイティブなオブジェクトに変わるかは、いずれにしても、一意のキーであるかどうかに関係なく、環境と状況に完全に依存します。

0
xthr33

C#では、Dictionary<string, string>に逆シリアル化すると、最後のキーと値のペアが使用されます。

string json = @"{""a"": ""x"", ""a"": ""y""}";
var d = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
// { "a" : "y" }

にデシリアライズしようとすると

class Foo
{
    [JsonProperty("a")]
    public string Bar { get; set; }

    [JsonProperty("a")]
    public string Baz { get; set; }
}

var f = JsonConvert.DeserializeObject<Foo>(json);

Newtonsoft.Json.JsonSerializationException例外が発生します。

0
Sam Leach

標準はこれを言っています:

プログラミング言語は、オブジェクトをサポートするかどうか、またサポートする場合はオブジェクトが提供する特性と制約によって大きく異なります。オブジェクトシステムのモデルは大きく異なる可能性があり、進化を続けています。 JSONは代わりに、名前/値のペアのコレクションを表現するための簡単な表記法を提供します。ほとんどのプログラミング言語には、そのようなコレクションを表すための機能があり、レコード、構造体、辞書、マップ、ハッシュ、オブジェクトなどの名前で指定できます。

バグは少なくともnode.jsにあります。このコードはnode.jsで成功します。

try {
     var json = {"name":"n","name":"v"};
     console.log(json); // outputs { name: 'v' }
} catch (e) {
     console.log(e);
}
0
John Carlson