JSON構文では、オブジェクトの重複キーを使用できますか?


205

これは有効なjsonですか?

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

http://jsonlint.com/は「はい」と言っています。

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

しかし、明らかにそれはあまり意味がありませんね。ほとんどの実装ではおそらくハッシュテーブルを使用するため、とにかくオーバーライドされます。


1
C#のJson.NETは、aに逆シリアル化すると、最初のキーペアを削除しますDictionary<string, string>
Sam Leach

JSON文字列の重複値を見つけるための解決策を期待して誰かがここに到着した場合は、無料のオンラインjsonバリデーターを
Pepijn Olivier

jsonlint.comは「はい」と言っています。そうではなく、最後のキーと値のペアを除くすべてを削除して検証します。これにより有効になります
Tim

7
その後、基準は破られます
ブラッドトーマス

1
キー名「-」をコメントとして使用し、値はコメントとして単一の文字列行です。だから私はパーサーがそれについて文句を言ってくれないことを願っています。
Lothar

回答:


126

標準から(p。ii)

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

標準(p。2)のさらに下に、JSONオブジェクトの仕様を示します。

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

Diagram for JSON Object

重複するキーが無効または有効であることについては触れていません。そのため、仕様によると、私はそれらが許可されていることを意味すると安全に想定しています。

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

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


5
私はこれを答えとして受け入れることができると思いますが、@ PatrickGoleyの言及が好きですが、json.orgでは、一意性を意味するキー/値のペアのセットと呼ばれ、無効であることを意味します。
2014

8
@clamp json.orgは標準ではなく、私が知る限り、Emca Internationalによって運営されていません。json.orgは匿名で表示されているようです。これは仕様:ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdfそれはjson.orgに言うことは関係ありません。
ティモシーシールズ

5
@clamp std::multimap今追加した例を考えてみましょう。キーが重複する可能性のあるJSONオブジェクトとしてシリアル化できます。
ティモシーシールド

1
@clampがキーと値のペアのセットであることは、重複した名前を排除しません。{"a":1,"a":2}2つの異なるキーと値のペアのセットです。実際、{"a":1,"a":1}たった1つの要素しか持たないキー/値ペアのセットと考えることもできます。それが繰り返されるという事実は、単なる構文上の癖と考えることができます。より適切な定義は、「オブジェクトは文字列(名前)から値への部分的な関数です」です。
Marcelo Cantos

2
@TimothyShieldsそして、あなたがリンクしたその標準は、「JSON構文は名前として使用される文字列に制限を課さず、名前文字列が一意である必要はなく、名前/値ペアの順序に重要性を割り当てません」と述べています
Charles

135

短い答え:はい、しかしお勧めできません。
長い答え:それはあなたが有効と呼ぶものに依存します...


ECMA-404「JSONデータ交換構文」は、重複した名前(キー)について何も述べていません。


ただし、RFC 8259「JavaScript Object Notation(JSON)Data Interchange Format」には次のように記載されています。

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

この文脈においてSHOULDで指定されるように理解されなければならないBCP 14

すべきである。この単語、あるいは形容詞「推奨」は、そこに特定の項目を無視する特定の事情の正当な理由が存在するかもしれないが、完全な意味合いが異なるコースを選択する前に理解し、慎重に検討しなければならないということを意味します。


RFC 8259は、一意の名前(キー)が優れている理由を説明しています。

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



また、セルゲイがコメントで指摘したように、ECMA-262「ECMAScript®言語仕様」は次のように述べています。

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

言い換えれば、最後の価値が勝ちます。


JSONの作成者であるDouglas CrockfordによるJava実装で名前が重複している文字列を解析しようとすると、例外が発生します

org.json.JSONException: Duplicate key "status"  at
org.json.JSONObject.putOnce(JSONObject.java:1076)

1
JSONは有効なJavaScriptであることが想定されているため、重複キーがリテラルで有効なJSであるかどうかを確認することは重要です。V8はそれらを受け入れているようです。d8 -e 'x={"a":1,"a":2}; print(x.a);'これは2を出力します
Ben Crowell

5
また、ECMA-262仕様はJSON.parse()明示的に述べていますIn the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.(つまり、最後の値が優先されます)。
セルゲイ2016年

4
@BenCrowellは:私の知る限りでは、JSONはJavaScriptが有効であることと、そうでない場合があり、見ることが想定されていないtimelessrepo.com/json-isnt-a-javascript-subsetを。そうは言っても、それはもちろんJavaScriptに強く触発されたものです(JSON仕様でもそうです)。
Simon Touchtech 2016

2
JavaScriptの「ストリクトモード」を使用する場合、2つの同一のキーがある場合、クロムは2番目のキーと値のペアを使用し、最初のキーを無視することに注意してください。IE11は例外をスローします。
Shahar、2017

18

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

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

受け入れられた回答は最初の文書から引用します。1番目のドキュメントの方がわかりやすいと思いますが、2番目のドキュメントの方が詳細です。

2番目のドキュメントは言う:

  1. オブジェクト

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

したがって、重複した名前を持つことは禁止されていませんが、お勧めしません。


10

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

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

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

これをJSONに変換すると、次のようになります。

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

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

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


5

JSON仕様は次のように述べています。

オブジェクトは、名前と値のペアの順不同のセットです。

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

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

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


23
無秩序は一意性を意味しますか?セットはここでの効果的な言葉だと思います
Patrick Goley 14

8
色の順不同のコレクション:青、緑、緑、青、赤、青、緑-重複しています。
ティモシーシールド

5
あなたが引用しているテキストフレーズ「オブジェクトは名前と値のペアの順序付けられていないセットです」はJSON仕様に表示されません...
Timothy Shields

6
json.orgを引用しているようです。公式には「近い」のですが、仕様ではありません。ページの上部には仕様へのリンクがあり、json.orgで逐語的に繰り返されています。仕様を検索すると、「unordered」という単語は表示されず、「set」という単語はJSONオブジェクトに関連しないコンテキストでのみ表示されます。
ティモシーシールド

5
名前と値のペアの順序付けられていないセット」とあり、名前ではなくペアであることに注意してください。つまり、{ (a,b), (a,c) } あるユニークなセット。したがって、技術的にはjson.orgの定義の下で{"a":1,"a":2}は有効ですが無効です{"a":1,"a":2,"a":1}。また、なお、ECMA-404(実際の標準)が単語「セット」を使用して回避:An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.
セルゲイ

3

一意である必要がありますが、一意である必要はありません。ただし、前述のように、一部のパーサーは失敗し、他のパーサーは解析された最後の値を使用するだけです。ただし、仕様を少し整理して重複を許可すると、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>

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


最初の例の配列にはコンマがありません。また、それ自体と矛盾しています。辞書を順序付けられたコレクションとして使用する場合、外部配列もオブジェクトにする必要があります。すなわち、{"div":{"p":"hello","p":"universe"}, "div":{"h1":"Heading 1","p":"another paragraph"}}。現在、多くの人やフレームワークがJSONオブジェクトを順不同の辞書として扱っていますが、JavaScriptやMongoDBのAPIなどは、ディクショナリ内のキーの順序に依存しているため、提案されているもの(順序付きディクショナリ)は前例のないものではありません。専用のパーサーが必要です。
ビンキ2017

2

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

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

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

私たちのJSONのサンプルをコメントに重複キーを使用します。例:

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

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

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


これは悪い考えです。重複するキーを含めることで、データを読み取る必要がない場合でも、未定義の動作に依存します。CrockfordのJSON-javaパーサーなどの一部のパーサーは、例外をスローし、データの解析を拒否します。
Richard Smith

実際、私たちの環境では完全に機能しているので、仕様に
合わ

@RichardSmithパーサーと新しいES仕様で動作が定義されていると思います。
ビンキ2017

2

投稿については、標準に関する多くの古いアイデアと混乱があるため、回答してください。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があることを示唆している標準が、このサイトは権威ではありません。ECMAを権限と見なすことは公平だと思いますが、ここで重要なことは、(一意のキーに関する)標準間の唯一の違いは、RFC 8259はキー一意である必要があると述べており、ECMA-404はそれらは必須ではないと述べていることですようにユニーク。

RFC-8259:

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

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

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

ECMA-404:

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

つまり、どのようにスライスしても、構文的に有効なJSONです。です。

RFC 8259で一意のキーが推奨されている理由は、

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

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


json.orgは実際にはECMAの標準化よりも古いものです。私はそれが実際にCrockford自身によってセットアップされたと信じています(それが彼の本に恥知らずなプラグがある理由です)。その時点で、それはJSONの権威でした。
最大

1

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

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

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

これになる:

Object {a: 3, b: 2}

しかし、あなたがギャンブラーでないなら、それを当てにしないください!


1

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

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

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

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

1
これはバグではなく、引用したセクションではその理由を説明しています。言語によって動作が異なり、JSONパーサーはその言語にとって最も自然な動作をします。いずれにせよ、この回答はuser454322が上記でまだ述べていないものを追加しません。
Richard Smith

1

RFC-7159によると、インターネット技術標準化委員会(IETF)によって発行されたJSONの現在の標準では、「オブジェクト内の名前は一意である必要があります」と記載されています。ただし、IETF文書で使用される用語を定義しているRFC-2119によると、「すべき」という言葉は実際には「...別のコースを選択する前に慎重に検討しました。」これが本質的に意味することは、一意のキーを持つことをお勧めしますが、必須ではないということです。JSONオブジェクトに重複したキーを含めることができますが、それはまだ有効です。

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


0

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例外を。


2
それはほとんど(すべてではないにしても)の実装が行うことだと思いますが、JSONの仕様の時点で有効であるかどうかは質問の答えにはなりません。
2014

@svidgen:これは、Microsoftの実装でもありません...サードパーティのライブラリです。
BoltClock

@BoltClockああ、タッチ。
svidgen 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.