Erlaubt die JSON-Syntax doppelte Schlüssel in einem Objekt?


205

Ist das gültig json?

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

http://jsonlint.com/ sagt ja.

http://www.json.org/ sagt nichts darüber aus, dass es verboten ist.

Aber offensichtlich macht es nicht viel Sinn, oder? Die meisten Implementierungen verwenden wahrscheinlich eine Hashtabelle, sodass sie sowieso überschrieben wird.


1
Json.NET von C # entfernt das erste Schlüsselpaar, wenn Sie zu einemDictionary<string, string>
Sam Leach

Falls jemand hier ankommt und auf eine Lösung hofft, um doppelte Werte in JSON-Zeichenfolgen zu finden,
Pepijn Olivier

jsonlint.com sagt ja. es tut nicht, es entfernt alle außer dem letzten Schlüssel-Wert-Paar und validiert es dann, was es gültig macht
Tim

7
Dann ist der Standard gebrochen
Brad Thomas

1
Ich habe den Schlüsselnamen "-" als Kommentar verwendet und der Wert ist eine einzelne Zeichenfolge als Kommentar. Ich hoffe also, dass sich kein Parser darüber beschweren wird.
Lothar

Antworten:


126

Aus dem Standard (S. ii) :

Es wird erwartet, dass sich andere Standards auf diesen beziehen, wobei das JSON-Textformat strikt eingehalten wird, während verschiedene Codierungsdetails eingeschränkt werden. Solche Standards können bestimmte Verhaltensweisen erfordern. JSON selbst gibt kein Verhalten an.

Weiter unten im Standard (S. 2) die Spezifikation für ein JSON-Objekt:

Eine Objektstruktur wird als ein Paar von Token mit geschweiften Klammern dargestellt, die null oder mehr Name / Wert-Paare umgeben. Ein Name ist eine Zeichenfolge. Jedem Namen folgt ein einzelnes Doppelpunkt-Token, das den Namen vom Wert trennt. Ein einzelnes Komma-Token trennt einen Wert von einem folgenden Namen.

Diagramm für JSON-Objekt

Es wird nicht erwähnt, dass doppelte Schlüssel ungültig oder gültig sind. Daher würde ich gemäß der Spezifikation davon ausgehen, dass dies bedeutet, dass sie zulässig sind.

Dass die meisten Implementierungen von JSON - Bibliotheken haben nicht akzeptieren Nachschlüssel nicht Konflikt mit dem Standard, weil des ersten Zitats.

Hier sind zwei Beispiele für die C ++ - Standardbibliothek. Wenn Sie ein JSON-Objekt in ein deserialisieren, ist std::mapes sinnvoll, doppelte Schlüssel abzulehnen. Wenn Sie jedoch ein JSON-Objekt in ein deserialisieren, ist std::multimapes sinnvoll, doppelte Schlüssel wie gewohnt zu akzeptieren.


5
Ich denke, ich kann dies als Antwort akzeptieren, obwohl ich die Erwähnung von @PatrickGoley mag, dass es auf json.org eine Menge von Schlüssel / Wert-Paaren genannt wird, was eine Eindeutigkeit impliziert, was bedeuten würde, dass es nicht gültig ist.
Klemme

8
@clamp json.org ist nicht der Standard und wird, soweit ich das beurteilen kann, nicht von Emca International betrieben. json.org scheint anonym präsentiert zu werden. Dies ist die Spezifikation: ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf Was auf json.org steht, ist nicht relevant.
Timothy Shields

5
@clamp Betrachten Sie das std::multimapBeispiel, das ich gerade hinzugefügt habe. Es kann als JSON-Objekt mit möglicherweise doppelten Schlüsseln serialisiert werden.
Timothy Shields

1
@clamp als Satz von Schlüssel / Wert-Paaren schließt doppelte Namen nicht aus. {"a":1,"a":2}ist ein Satz von zwei unterschiedlichen Schlüssel / Wert-Paaren. Man {"a":1,"a":1}könnte sich sogar eine Menge von Schlüssel / Wert-Paaren vorstellen, die zufällig nur ein Element haben. Die Tatsache, dass es wiederholt wird, kann nur als syntaktische Eigenart betrachtet werden. Eine bessere Definition wäre: "Ein Objekt ist eine Teilfunktion von Zeichenfolgen (Namen) zu Werten."
Marcelo Cantos

2
@TimothyShields Und dieser Standard, auf den Sie verlinkt haben, lautet: "Die JSON-Syntax legt keine Einschränkungen für die als Namen verwendeten Zeichenfolgen fest, erfordert nicht, dass Namenszeichenfolgen eindeutig sind, und weist der Reihenfolge der Name / Wert-Paare keine Bedeutung zu."
Charles

135

Die kurze Antwort: Ja, wird aber nicht empfohlen.
Die lange Antwort: Es kommt darauf an, was Sie als gültig bezeichnen ...


ECMA-404 "Die JSON-Datenaustauschsyntax" sagt nichts über doppelte Namen (Schlüssel) aus.


In RFC 8259 "Das JSON-Datenaustauschformat (JavaScript Object Notation)" heißt es jedoch:

Die Namen innerhalb eines Objekts sollten eindeutig sein.

In diesem Zusammenhang MUSS verstanden werden, wie in BCP 14 angegeben :

SOLLTE Dieses Wort oder das Adjektiv "EMPFOHLEN" bedeuten, dass es unter bestimmten Umständen gültige Gründe geben kann, einen bestimmten Gegenstand zu ignorieren, aber die vollständigen Auswirkungen müssen verstanden und sorgfältig abgewogen werden, bevor ein anderer Kurs gewählt wird.


RFC 8259 erklärt, warum eindeutige Namen (Schlüssel) gut sind:

Ein Objekt, dessen Namen alle eindeutig sind, ist in dem Sinne interoperabel, dass alle Softwareimplementierungen, die dieses Objekt empfangen, sich auf die Namens-Wert-Zuordnungen einigen. Wenn die Namen innerhalb eines Objekts nicht eindeutig sind, ist das Verhalten von Software, die ein solches Objekt empfängt, nicht vorhersehbar. Viele Implementierungen melden nur das Nachname / Wert-Paar. Andere Implementierungen melden einen Fehler oder können das Objekt nicht analysieren, und einige Implementierungen melden alle Name / Wert-Paare, einschließlich Duplikate.



Wie Serguei in den Kommentaren ausführte: ECMA-262 "ECMAScript® Language Specification" lautet:

Wenn innerhalb eines Objekts doppelte Namenszeichenfolgen vorhanden sind, werden die lexikalisch vorangestellten Werte für denselben Schlüssel überschrieben.

Mit anderen Worten, der letzte Wert gewinnt.


Der Versuch, eine Zeichenfolge mit doppelten Namen mit der Java-Implementierung von Douglas Crockford (dem Ersteller von JSON) zu analysieren, führt zu einer Ausnahme :

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

1
JSON soll gültiges Javascript sein, daher ist es wichtig zu prüfen, ob doppelte Schlüssel in Literalen gültiges JS sind. V8 scheint sie zu akzeptieren: d8 -e 'x={"a":1,"a":2}; print(x.a);'Dies druckt 2.
Ben Crowell

5
Auch die ECMA-262- Spezifikation für JSON.parse()sagt explizit In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.(mit anderen Worten, der letzte Wert gewinnt).
Serguei

4
@ BenCrowell: Soweit ich weiß, soll JSON kein gültiges JavaScript sein, und es gibt Fälle, in denen dies nicht der Fall ist, siehe timelessrepo.com/json-isnt-a-javascript-subset . Trotzdem wurde es natürlich stark von JavaScript inspiriert (dies steht sogar in der JSON-Spezifikation).
Simon Touchtech

2
Es ist erwähnenswert, dass bei Verwendung des "strengen Modus" von Javascript bei zwei identischen Schlüsseln Chrome das zweite Schlüssel-Wert-Paar verwendet und das erste ignoriert. IE11 löst eine Ausnahme aus.
Shahar

18

Es gibt 2 Dokumente, die das JSON-Format angeben:

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

Die akzeptierte Antwort zitiert aus dem 1. Dokument. Ich denke, das erste Dokument ist klarer, aber das zweite enthält mehr Details.

Das 2. Dokument sagt:

  1. Objekte

    Eine Objektstruktur wird als ein Paar geschweifter Klammern dargestellt, die null oder mehr Name / Wert-Paare (oder Elemente) umgeben. Ein Name ist eine Zeichenfolge. Nach jedem Namen steht ein einzelner Doppelpunkt, der den Namen vom Wert trennt. Ein einzelnes Komma trennt einen Wert von einem folgenden Namen. Die Namen innerhalb eines Objekts sollten eindeutig sein.

Es ist also nicht verboten, einen doppelten Namen zu haben, aber es wird davon abgeraten.


10

Ich bin auf eine ähnliche Frage gestoßen, als ich mich mit einer API befasst habe, die sowohl XML als auch JSON akzeptiert, aber nicht dokumentiert, wie sie damit umgehen würde, was Sie erwarten würden, wenn doppelte Schlüssel in JSON akzeptiert werden.

Das Folgende ist eine gültige XML-Darstellung Ihres Beispiel-JSON:

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

Wenn dies in JSON konvertiert wird, erhalten Sie Folgendes:

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

Eine natürliche Zuordnung von einer Sprache, die doppelte Schlüssel verarbeitet, kann hier als potenzielle Referenz für bewährte Verfahren dienen.

Hoffe das hilft jemandem!


5

Die JSON-Spezifikation sagt dies:

Ein Objekt ist eine ungeordnete Menge von Name / Wert-Paaren.

Der wichtige Teil hier ist "ungeordnet": Es impliziert die Eindeutigkeit von Schlüsseln, da das einzige, was Sie verwenden können, um auf ein bestimmtes Paar zu verweisen, dessen Schlüssel ist.

Darüber hinaus deserialisieren die meisten JSON-Bibliotheken JSON-Objekte in Hash-Maps / Wörterbücher, bei denen Schlüssel garantiert eindeutig sind. Was passiert, wenn Sie ein JSON-Objekt mit doppelten Schlüsseln deserialisieren, hängt von der Bibliothek ab: In den meisten Fällen wird entweder eine Fehlermeldung angezeigt oder nur der letzte Wert für jeden doppelten Schlüssel wird berücksichtigt.

Gibt in Python beispielsweise json.loads('{"a": 1, "a": 2}')zurück {"a": 2}.


23
bedeutet ungeordnet Einzigartigkeit? Ich denke, Set ist das maßgebliche Wort hier
Patrick Goley

8
Eine ungeordnete Sammlung von Farben: Blau, Grün, Grün, Blau, Rot, Blau, Grün - Es hat Duplikate.
Timothy Shields

5
Die von Ihnen zitierte Textphrase "Ein Objekt ist eine ungeordnete Menge von Name / Wert-Paaren" erscheint nicht in der JSON-Spezifikation ...
Timothy Shields

6
Ich sehe jetzt, dass Sie json.org zitiert haben. Es ist "nah" am offiziellen, aber es ist nicht die Spezifikation. Oben auf der Seite befindet sich ein Link zur Spezifikation, der auf json.org wörtlich wiederholt wird. Wenn Sie die Spezifikation durchsuchen, wird das Wort "ungeordnet" nicht angezeigt, und das Wort "set" wird nur in Kontexten angezeigt, die nicht mit JSON-Objekten zusammenhängen.
Timothy Shields

5
Beachten Sie, dass dort "ungeordnete Menge von Name / Wert-Paaren " steht, Paare keine Namen. Das heißt, { (a,b), (a,c) } ist ein einzigartiges Set. Technisch gesehen ist die Definition unter json.org {"a":1,"a":2}also gültig, aber {"a":1,"a":2,"a":1}nicht. Beachten Sie auch, dass ECMA-404 (der eigentliche Standard) die Verwendung des Wortes "set" vermeidet:An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.
Serguei

3

SOLLTE einzigartig sein bedeutet nicht, MUSS einzigartig sein. Wie bereits erwähnt, würden einige Parser jedoch fehlschlagen und andere würden nur den zuletzt analysierten Wert verwenden. Wenn die Spezifikation jedoch ein wenig bereinigt wurde, um Duplikate zuzulassen, könnte ich eine Verwendung sehen, bei der Sie möglicherweise einen Ereignishandler haben, der JSON in HTML oder ein anderes Format umwandelt. In solchen Fällen wäre dies vollkommen gültig Analysieren Sie den JSON und erstellen Sie ein anderes Dokumentformat ...

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

könnte dann zum Beispiel leicht zu HTML analysieren

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

Ich kann die Gründe für die Frage sehen, aber so wie es aussieht ... würde ich ihr nicht vertrauen.


Im Array Ihres ersten Beispiels fehlt ein Komma. Es ist auch nicht mit sich selbst vereinbar. Wenn Sie ein Wörterbuch als geordnete Sammlung verwenden möchten, sollte Ihr äußeres Array auch nur ein Objekt sein. Dh {"div":{"p":"hello","p":"universe"}, "div":{"h1":"Heading 1","p":"another paragraph"}}. Viele Menschen und Frameworks behandeln JSON-Objekte als ungeordnete Wörterbücher, aber JavaScript und z. B. die API von MongoDB basieren auf der Reihenfolge der Schlüssel in Wörterbüchern. Was Sie also vorschlagen (geordnete Wörterbücher), ist nicht ungewöhnlich. Sie brauchen nur einen speziellen Parser.
Binki

2

Nach dem Zweck fragen gibt es verschiedene Antworten:

Bei Verwendung von JSON zum Serialisieren von Objekten (JavaScriptObjectNotation) wird jedes Wörterbuchelement einer einzelnen Objekteigenschaft zugeordnet, sodass unterschiedliche Einträge, die einen Wert für dieselbe Eigenschaft definieren, keine Bedeutung haben.

Ich bin jedoch auf dieselbe Frage aus einem ganz bestimmten Anwendungsfall gestoßen: Beim Schreiben von JSON-Beispielen für API-Tests habe ich mich gefragt, wie ich Kommentare in unsere JSON-Datei einfügen kann, ohne die Benutzerfreundlichkeit zu beeinträchtigen. Die JSON-Spezifikation kennt keine Kommentare, daher habe ich einen sehr einfachen Ansatz gefunden:

So verwenden Sie doppelte Schlüssel zum Kommentieren unserer JSON-Beispiele . Beispiel:

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

Die von uns verwendeten JSON-Serialisierer haben keine Probleme mit diesen "REMARK" -Duplikaten, und unser Anwendungscode ignoriert diesen kleinen Aufwand einfach.

Obwohl die Anwendungsschicht keine Bedeutung hat, bieten diese Duplikate für uns eine wertvolle Problemumgehung, um unseren Testbeispielen Kommentare hinzuzufügen, ohne die Benutzerfreundlichkeit des JSON zu beeinträchtigen.


Das ist eine schlechte Idee. Durch das Einfügen doppelter Schlüssel verlassen Sie sich auf undefiniertes Verhalten, auch wenn Sie die darin enthaltenen Daten nicht lesen müssen. Einige Parser, wie beispielsweise der JSON-Java-Parser von Crockford, lösen eine Ausnahme aus und lehnen es ab, die Daten zu analysieren.
Richard Smith

Eigentlich perfekt in unserer Umgebung arbeiten, also meinen Bedürfnissen gerecht werden, obwohl ich Ihnen zustimme, dass es eine Art von Spezifikation ist;)
aknoepfel

@RichardSmith Ich würde sagen, die Parser und neueren ES-Spezifikationen haben das Verhalten definiert.
Binki

2

Posten und Antworten, weil es viele veraltete Ideen und Verwirrung über die Standards gibt. Ab Dezember 2017 gibt es zwei konkurrierende Standards:

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

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

json.org schlägt vor, dass ECMA-404 der Standard ist, aber diese Seite scheint keine Autorität zu sein. Während ich es ist fair zu betrachten ECMA die Autorität denke, was hier wichtig ist, ist der einzige Unterschied zwischen den Standards ( in Bezug auf eindeutige Schlüssel) , dass RFC 8259 sagt der Schlüssel sollte eindeutig sein, und die ECMA-404 sagt , sie sind nicht erforderlich sein , einzigartig.

RFC-8259:

"Die Namen innerhalb eines Objekts sollten eindeutig sein."

Das Wort "sollte" in allen Großbuchstaben hat eine Bedeutung innerhalb der RFC-Welt, die in einem anderen Standard (BCP 14, RFC 2119 - https://tools.ietf.org/html/rfc2119 ) als definiert ist.

  1. SOLLTE Dieses Wort oder das Adjektiv "EMPFOHLEN" bedeuten, dass es unter bestimmten Umständen gültige Gründe geben kann, einen bestimmten Gegenstand zu ignorieren, aber die vollständigen Auswirkungen müssen verstanden und sorgfältig abgewogen werden, bevor ein anderer Kurs gewählt wird.

ECMA-404:

"Die JSON-Syntax legt keine Einschränkungen für die als Namen verwendeten Zeichenfolgen fest, erfordert nicht, dass Namenszeichenfolgen eindeutig sind, und weist der Reihenfolge der Name / Wert-Paare keine Bedeutung zu."

Egal wie Sie es schneiden, es ist syntaktisch gültiges JSON .

Der Grund für die eindeutige Schlüsselempfehlung in RFC 8259 ist:

Ein Objekt, dessen Namen alle eindeutig sind, ist in dem Sinne interoperabel, dass alle Softwareimplementierungen, die dieses Objekt empfangen, sich auf die Namens-Wert-Zuordnungen einigen. Wenn die Namen innerhalb eines Objekts nicht eindeutig sind, ist das Verhalten von Software, die ein solches Objekt empfängt, nicht vorhersehbar. Viele Implementierungen melden nur das Nachname / Wert-Paar. Andere Implementierungen melden einen Fehler oder können das Objekt nicht analysieren, und einige Implementierungen melden alle Name / Wert-Paare, einschließlich Duplikate.

Mit anderen Worten, aus Sicht von RFC 8259 ist es gültig, aber Ihr Parser kann barf und es gibt kein Versprechen, welcher Wert, falls vorhanden, mit diesem Schlüssel gepaart wird. Aus der Sicht von ECMA-404 (die ich persönlich als Autorität betrachten würde) ist dies gültig. Für mich bedeutet dies, dass jeder Parser, der sich weigert, ihn zu analysieren, kaputt ist. Es sollte zumindest nach diesen beiden Standards analysiert werden. Aber wie es zu einem nativen Objekt Ihrer Wahl wird, hängt auf jeden Fall von eindeutigen Schlüsseln ab oder nicht, die vollständig von der Umgebung und der Situation abhängen, und nichts davon ist zunächst im Standard enthalten.


json.org ist tatsächlich älter als die ECMA-Standardisierung. Ich glaube, es wurde tatsächlich von Crockford selbst eingerichtet (weshalb es einen schamlosen Stecker für sein Buch hat). Zu diesem Zeitpunkt war es die Autorität für JSON.
Max

1

Es ist nicht im ECMA JSON-Standard definiert . Und im Allgemeinen bedeutet ein Mangel an Definition in einem Standard: "Verlassen Sie sich nicht darauf, dass dies überall gleich funktioniert."

Wenn Sie ein Spieler sind, erlauben "viele" JSON-Engines das Duplizieren und verwenden einfach den zuletzt angegebenen Wert. Dies:

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

Wird dies:

Object {a: 3, b: 2}

Aber wenn Sie kein Spieler sind, zählen Sie nicht darauf!


1

Der Standard sagt dies:

Programmiersprachen unterscheiden sich stark darin, ob sie Objekte unterstützen und wenn ja, welche Eigenschaften und Einschränkungen die Objekte bieten. Die Modelle von Objektsystemen können sehr unterschiedlich sein und entwickeln sich weiter. JSON bietet stattdessen eine einfache Notation zum Ausdrücken von Sammlungen von Name / Wert-Paaren. Die meisten Programmiersprachen verfügen über eine Funktion zur Darstellung solcher Sammlungen, die Namen wie Datensatz, Struktur, Diktat, Karte, Hash oder Objekt enthalten können.

Der Fehler ist mindestens in node.js. Dieser Code ist in node.js erfolgreich.

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

1
Es ist kein Fehler, und der von Ihnen zitierte Abschnitt erklärt, warum dies nicht der Fall ist: Verschiedene Sprachen verhalten sich unterschiedlich, und JSON-Parser tun das, was für diese Sprache am natürlichsten ist. In jedem Fall fügt diese Antwort nichts hinzu, was user454322 oben noch nicht gesagt hat.
Richard Smith

1

Gemäß RFC-7159, dem aktuellen Standard für JSON, der von der Internet Engineering Task Force (IETF) veröffentlicht wurde, heißt es: "Die Namen innerhalb eines Objekts sollten eindeutig sein." Gemäß RFC-2119, das die in IETF-Dokumenten verwendete Terminologie definiert, bedeutet das Wort "sollte" tatsächlich "... es kann unter bestimmten Umständen gültige Gründe geben, ein bestimmtes Element zu ignorieren, aber die vollständigen Auswirkungen müssen verstanden werden und sorgfältig abgewogen, bevor ein anderer Kurs gewählt wird. " Dies bedeutet im Wesentlichen, dass zwar eindeutige Schlüssel empfohlen werden, dies jedoch kein Muss ist. Wir können doppelte Schlüssel in einem JSON-Objekt haben, und es wäre immer noch gültig.

Aus der praktischen Anwendung habe ich gesehen, dass der Wert des letzten Schlüssels berücksichtigt wird, wenn doppelte Schlüssel in einem JSON gefunden werden.


0

Wenn Sie in C # zu a deserialisieren, Dictionary<string, string>wird das letzte Schlüsselwertpaar verwendet:

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

wenn Sie versuchen, zu deserialisieren

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

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

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

Du bekommst eine Newtonsoft.Json.JsonSerializationExceptionAusnahme.


2
Ich denke, das ist es, was die meisten (wenn nicht alle) Implementierungen tun, aber es beantwortet meine Frage nicht, ob es ab der Spezifikation von JSON gültig ist.
Klemme

@svidgen: Dies ist nicht einmal die Implementierung von Microsoft ... es ist eine Bibliothek von Drittanbietern.
BoltClock

@ BoltClock Ah, touche.
Svidgen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.