La syntaxe JSON autorise-t-elle la duplication des clés dans un objet?


205

Est-ce un json valide?

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

http://jsonlint.com/ dit oui.

http://www.json.org/ ne dit rien sur l'interdiction.

Mais évidemment, cela n'a pas beaucoup de sens, n'est-ce pas? La plupart des implémentations utilisent probablement une table de hachage donc elle est de toute façon annulée.


1
Json.NET de C # supprime la première paire de clés si vous désérialisez en unDictionary<string, string>
Sam Leach

Si quelqu'un arrive ici en espérant une solution pour trouver des valeurs en double dans les chaînes JSON, consultez le validateur json en ligne gratuit
Pepijn Olivier

jsonlint.com dit oui. il ne le fait pas, il supprime tout sauf la dernière paire clé-valeur, puis le valide, ce qui le rend valide
Tim

7
Ensuite, la norme est brisée
Brad Thomas

1
J'ai utilisé le nom de clé "-" comme commentateur et la valeur est une seule ligne de chaîne comme commentaire. J'espère donc qu'aucun analyseur ne s'en plaindra.
Lothar

Réponses:


126

De la norme (p. Ii) :

Il est prévu que d'autres normes se réfèrent à celui-ci, respectant strictement le format de texte JSON, tout en imposant des restrictions sur divers détails d'encodage. Ces normes peuvent nécessiter des comportements spécifiques. JSON lui-même ne spécifie aucun comportement.

Plus bas dans la norme (p. 2), la spécification d'un objet JSON:

Une structure d'objet est représentée comme une paire de jetons entre crochets entourant zéro ou plusieurs paires nom / valeur. Un nom est une chaîne. Un seul jeton deux-points suit chaque nom, séparant le nom de la valeur. Un seul jeton virgule sépare une valeur d'un nom suivant.

Diagramme pour un objet JSON

Il ne fait aucune mention de clés en double non valides ou valides, donc selon la spécification, je suppose que cela signifie qu'elles sont autorisées.

Le fait que la plupart des implémentations des bibliothèques JSON n'acceptent pas les clés en double n'entre pas en conflit avec la norme, en raison de la première citation.

Voici deux exemples liés à la bibliothèque standard C ++. Lors de la désérialisation d'un objet JSON en un, std::mapil serait logique de refuser les clés en double. Mais lors de la désérialisation d'un objet JSON en un, std::multimapil serait logique d'accepter les clés en double comme d'habitude.


5
Je suppose que je peux accepter cela comme une réponse, bien que j'aime la mention de @PatrickGoley selon laquelle sur json.org, cela s'appelle un ensemble de paires clé / valeur qui implique l'unicité qui signifierait qu'elle n'est pas valide.
clamp

8
@clamp json.org n'est pas la norme et, pour autant que je sache, n'est pas géré par Emca International. json.org semble présenté de manière anonyme. Voici la spécification: ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf Ce qu'elle dit sur json.org n'est pas pertinent.
Timothy Shields

5
@clamp Considérez l' std::multimapexemple que je viens d'ajouter. Il peut être sérialisé en tant qu'objet JSON avec des clés potentiellement dupliquées.
Timothy Shields

1
@clamp étant un ensemble de paires clé / valeur n'empêche pas les noms en double. {"a":1,"a":2}est un ensemble de deux paires clé / valeur distinctes. En effet, même {"a":1,"a":1}pourrait être considéré comme un ensemble de paires clé / valeur qui se trouve n'avoir qu'un seul élément. Le fait qu'il soit répété peut être considéré comme une simple bizarrerie syntaxique. Une meilleure définition serait, "Un objet est une fonction partielle des chaînes (noms) aux valeurs."
Marcelo Cantos

2
@TimothyShields Et cette norme à laquelle vous avez lié dit: "La syntaxe JSON n'impose aucune restriction sur les chaînes utilisées comme noms, n'exige pas que les chaînes de nom soient uniques et n'attribue aucune signification à l'ordre des paires nom / valeur"
Charles

135

La réponse courte: oui mais n'est pas recommandée.
La réponse longue: cela dépend de ce que vous appelez valide ...


ECMA-404 "La syntaxe d'échange de données JSON" ne dit rien sur les noms (clés) dupliqués.


Cependant, la RFC 8259 "Le format d'échange de données JSON (JavaScript Object Notation)" dit:

Les noms dans un objet DEVRAIENT être uniques.

Dans ce contexte, DEVRAIT être compris comme spécifié dans le BCP 14 :

DEVRAIT Ce mot, ou l'adjectif «RECOMMANDÉ», signifie qu'il peut exister des raisons valables dans des circonstances particulières d'ignorer un élément particulier, mais toutes les implications doivent être comprises et soigneusement pesées avant de choisir un cours différent.


La RFC 8259 explique pourquoi les noms uniques (clés) sont bons:

Un objet dont les noms sont tous uniques est interopérable dans le sens où toutes les implémentations logicielles recevant cet objet seront d'accord sur les mappages nom-valeur. Lorsque les noms d'un objet ne sont pas uniques, le comportement du logiciel qui reçoit un tel objet est imprévisible. De nombreuses implémentations signalent uniquement la paire nom / valeur. D'autres implémentations signalent une erreur ou ne parviennent pas à analyser l'objet, et certaines implémentations signalent toutes les paires nom / valeur, y compris les doublons.



En outre, comme l'a souligné Serguei dans les commentaires: ECMA-262 "ECMAScript® Language Specification", se lit comme suit:

Dans le cas où il existe des chaînes de nom en double dans un objet, les valeurs lexicalement précédentes pour la même clé doivent être écrasées.

En d'autres termes, la dernière valeur l'emporte.


Essayer d'analyser une chaîne avec des noms en double avec l' implémentation Java par Douglas Crockford (le créateur de JSON) entraîne une exception :

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

1
JSON est censé être du javascript valide, il est donc pertinent de vérifier si les clés en double sont des JS valides dans les littéraux. V8 semble les accepter: d8 -e 'x={"a":1,"a":2}; print(x.a);'cela imprime 2.
Ben Crowell

5
La spécification ECMA-262 pour JSON.parse()explicitement dit In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.(en d'autres termes, la dernière valeur gagne).
Serguei

4
@BenCrowell: Pour autant que je sache, JSON n'est pas censé être un code JavaScript valide et il y a des cas où il ne l'est pas, voir timelessrepo.com/json-isnt-a-javascript-subset . Cela dit, il était bien sûr fortement inspiré par JavaScript (il le dit même dans la spécification JSON).
Simon Touchtech

2
Il convient de noter que lorsque vous utilisez le "mode strict" javascript, s'il existe deux clés identiques, Chrome utilisera la deuxième paire clé-valeur et ignorera la première. IE11 lèvera une exception.
Shahar

18

Il existe 2 documents spécifiant le format JSON:

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

La réponse acceptée cite le premier document. Je pense que le 1er document est plus clair, mais le 2e contient plus de détails.

Le 2ème document dit:

  1. Objets

    Une structure d'objet est représentée comme une paire de crochets entourant zéro ou plusieurs paires nom / valeur (ou membres). Un nom est une chaîne. Un deux-points vient après chaque nom, séparant le nom de la valeur. Une seule virgule sépare une valeur d'un nom suivant. Les noms dans un objet DEVRAIENT être uniques.

Il n'est donc pas interdit d'avoir un nom en double, mais il est déconseillé.


10

Je suis tombé sur une question similaire en traitant avec une API qui accepte à la fois XML et JSON, mais ne documente pas comment il gérerait ce que vous attendez d'être des clés en double dans le JSON accepté.

Voici une représentation XML valide de votre exemple JSON:

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

Lorsque cela est converti en JSON, vous obtenez les éléments suivants:

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

Un mappage naturel à partir d'un langage qui gère ce que vous pourriez appeler des clés en double dans un autre peut servir ici de référence potentielle aux meilleures pratiques.

J'espère que cela aide quelqu'un!


5

La spécification JSON dit ceci:

Un objet est un ensemble non ordonné de paires nom / valeur.

La partie importante ici est "non ordonnée": elle implique l'unicité des clés, car la seule chose que vous pouvez utiliser pour faire référence à une paire spécifique est sa clé.

De plus, la plupart des bibliothèques JSON désérialisent les objets JSON en cartes / dictionnaires de hachage, où les clés sont garanties uniques. Ce qui se passe lorsque vous désérialisez un objet JSON avec des clés en double dépend de la bibliothèque: dans la plupart des cas, vous obtiendrez soit une erreur, soit seule la dernière valeur de chaque clé en double sera prise en compte.

Par exemple, en Python, json.loads('{"a": 1, "a": 2}')renvoie {"a": 2}.


23
la non-commande implique-t-elle l'unicité? Je pense que l'ensemble est le mot
clé

8
Une collection de couleurs non ordonnée: Bleu, Vert, Vert, Bleu, Rouge, Bleu, Vert - Elle a des doublons.
Timothy Shields

5
La phrase textuelle que vous citez, "Un objet est un ensemble non ordonné de paires nom / valeur", n'apparaît pas dans la spécification JSON ...
Timothy Shields

6
Je vois maintenant que vous citiez json.org. C'est «proche» de l'officiel, mais ce n'est pas la spécification. Le haut de la page contient un lien vers la spécification, qui est répétée textuellement sur json.org. Si vous recherchez la spécification, le mot "non ordonné" n'apparaît pas et le mot "set" n'apparaît que dans des contextes sans rapport avec les objets JSON.
Timothy Shields

5
Notez qu'il dit "ensemble non ordonné de paires nom / valeur ", des paires et non des noms. Autrement dit, { (a,b), (a,c) } est un ensemble unique. Donc, techniquement, la définition json.org {"a":1,"a":2}est valide mais {"a":1,"a":2,"a":1}ne l'est pas. Notez également que l' ECMA-404 (la norme actuelle) évite d'utiliser le mot "set":An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.
Serguei

3

DEVRAIT être unique ne signifie pas DOIT être unique. Cependant, comme indiqué, certains analyseurs échoueraient et d'autres utiliseraient simplement la dernière valeur analysée. Cependant, si la spécification a été nettoyée un peu pour permettre les doublons, je pourrais voir une utilisation où vous pourriez avoir un gestionnaire d'événements qui transforme le JSON en HTML ou dans un autre format ... dans de tels cas, il serait parfaitement valide pour analyser le JSON et créer un autre format de document ...

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

pourrait alors facilement analyser en html par exemple

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

Je peux voir le raisonnement derrière la question, mais en l'état ... je n'y ferais pas confiance.


Il manque une virgule au tableau de votre premier exemple. En outre, il est incompatible avec lui-même. Si vous allez utiliser un dictionnaire comme collection ordonnée, votre tableau externe devrait également être simplement un objet. -À- dire, {"div":{"p":"hello","p":"universe"}, "div":{"h1":"Heading 1","p":"another paragraph"}}. Maintenant, beaucoup de gens et de frameworks traitent les objets JSON comme des dictionnaires non ordonnés, mais JavaScript et par exemple l'API de MongoDB reposent sur l'ordre des clés dans les dictionnaires, donc ce que vous suggérez (dictionnaires ordonnés) n'est pas inconnu. Vous auriez juste besoin d'un analyseur spécialisé.
binki

2

Demander à des fins, il existe différentes réponses:

À l'aide de JSON pour sérialiser des objets (JavaScriptObjectNotation), chaque élément de dictionnaire est mappé à une propriété d'objet individuelle, de sorte que différentes entrées définissant une valeur pour la même propriété n'ont aucune signification.

Cependant, je suis tombé sur la même question à partir d'un cas d'utilisation très spécifique: en écrivant des échantillons JSON pour les tests d'API, je me demandais comment ajouter des commentaires dans notre fichier JSON sans casser l'utilisabilité. La spécification JSON ne connaît pas les commentaires, j'ai donc proposé une approche très simple:

Pour utiliser des clés en double pour commenter nos exemples JSON . Exemple:

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

Les sérialiseurs JSON que nous utilisons n'ont aucun problème avec ces doublons "REMARK" et notre code d'application ignore simplement ce petit surcoût.

Ainsi, même s'il n'y a aucune signification sur la couche application, ces doublons pour nous fournissent une solution de contournement précieuse pour ajouter des commentaires à nos échantillons de test sans rompre l'utilisabilité du JSON.


C'est une mauvaise idée. En incluant des clés en double, même si vous n'avez pas besoin de lire les données qu'elles contiennent, vous comptez sur un comportement non défini. Certains analyseurs, comme l'analyseur JSON-java de Crockford, lèvent une exception et refusent d'analyser les données.
Richard Smith

En fait, fonctionnant parfaitement dans notre environnement, répondant ainsi à mes besoins, même si je suis d'accord avec vous que c'est une sorte de spécifications;)
aknoepfel

@RichardSmith Je dirais que les analyseurs et les nouvelles spécifications ES ont défini le comportement.
binki

2

Publication et réponse car il y a beaucoup d'idées obsolètes et de confusion sur les normes. En décembre 2017, il y avait deux normes concurrentes:

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

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

json.org suggère que l'ECMA-404 est la norme, mais ce site ne semble pas être une autorité. Bien que je pense qu'il est juste de considérer l'ECMA comme l'autorité, ce qui est important ici, c'est que la seule différence entre les normes (concernant les clés uniques) est que la RFC 8259 dit que les clés doivent être uniques, et l'ECMA-404 dit qu'elles ne sont pas tenues d'être unique.

RFC-8259:

"Les noms dans un objet DEVRAIENT être uniques."

Le mot "devrait" dans toutes les majuscules comme ça, a une signification dans le monde RFC, qui est spécifiquement définie dans une autre norme (BCP 14, RFC 2119 - https://tools.ietf.org/html/rfc2119 ) comme,

  1. DEVRAIT Ce mot, ou l'adjectif "RECOMMANDÉ", signifie qu'il peut exister des raisons valables dans des circonstances particulières d'ignorer un élément particulier, mais toutes les implications doivent être comprises et soigneusement pesées avant de choisir un cours différent.

ECMA-404:

"La syntaxe JSON n'impose aucune restriction sur les chaînes utilisées comme noms, n'exige pas que les chaînes de nom soient uniques et n'attribue aucune signification à l'ordre des paires nom / valeur."

Donc, peu importe la façon dont vous le découpez, il s'agit d'un JSON syntaxiquement valide .

La raison donnée pour la recommandation clé unique dans la RFC 8259 est,

Un objet dont les noms sont tous uniques est interopérable dans le sens où toutes les implémentations logicielles recevant cet objet seront d'accord sur les mappages nom-valeur. Lorsque les noms d'un objet ne sont pas uniques, le comportement du logiciel qui reçoit un tel objet est imprévisible. De nombreuses implémentations signalent uniquement la paire nom / valeur. D'autres implémentations signalent une erreur ou ne parviennent pas à analyser l'objet, et certaines implémentations signalent toutes les paires nom / valeur, y compris les doublons.

En d'autres termes, du point de vue RFC 8259, c'est valide mais votre analyseur peut aboyer et il n'y a aucune promesse quant à la valeur, le cas échéant, qui sera associée à cette clé. Du point de vue ECMA-404 (que je considérerais personnellement comme l'autorité), c'est valable, point final. Pour moi, cela signifie que tout analyseur qui refuse de l'analyser est brisé. Il doit au moins analyser selon ces deux normes. Mais la façon dont il devient votre objet natif de choix est, en tout cas, des clés uniques ou non, complètement dépendantes de l'environnement et de la situation, et rien de tout cela n'est dans la norme pour commencer.


json.org est en fait antérieur à la normalisation ECMA. Je crois qu'il a été installé par Crockford lui-même (c'est pourquoi il a une prise sans vergogne pour son livre). À ce moment-là, c'était l'autorité pour JSON.
max

1

Il n'est pas défini dans la norme ECMA JSON . Et d'une manière générale, un manque de définition dans une norme signifie: «Ne comptez pas sur ce fonctionnement partout de la même manière».

Si vous êtes un joueur, "de nombreux" moteurs JSON permettront la duplication et utiliseront simplement la dernière valeur spécifiée. Ce:

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

Devient ceci:

Object {a: 3, b: 2}

Mais si vous n'êtes pas un joueur, ne comptez pas dessus!


1

La norme dit ceci:

Les langages de programmation varient considérablement selon qu'ils prennent en charge des objets et, dans l'affirmative, quelles caractéristiques et contraintes offrent les objets. Les modèles de systèmes d'objets peuvent être très divergents et continuent d'évoluer. JSON fournit à la place une notation simple pour exprimer des collections de paires nom / valeur. La plupart des langages de programmation auront une fonction pour représenter de telles collections, qui peuvent s'appeler par des noms comme record, struct, dict, map, hash ou object.

Le bogue est au moins dans node.js. Ce code réussit dans node.js.

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

1
Ce n'est pas un bug, et la section que vous avez citée explique pourquoi ce n'est pas le cas: les différentes langues se comportent différemment, et les analyseurs JSON feront ce qui est le plus naturel pour cette langue. Dans tous les cas, cette réponse n'ajoute rien que user454322 n'ait déjà dit ci-dessus.
Richard Smith

1

Selon la RFC-7159, la norme actuelle pour JSON publiée par l'Internet Engineering Task Force (IETF), stipule que "les noms dans un objet DEVRAIENT être uniques". Cependant, selon la RFC-2119 qui définit la terminologie utilisée dans les documents de l'IETF, le mot "devrait" signifie en fait "... il peut exister des raisons valables dans des circonstances particulières d'ignorer un élément particulier, mais toutes les implications doivent être comprises et soigneusement pesé avant de choisir un cours différent. " Cela signifie essentiellement que bien qu'il soit recommandé d'avoir des clés uniques, ce n'est pas un must. Nous pouvons avoir des clés en double dans un objet JSON, et ce serait toujours valide.

De l'application pratique, j'ai vu que la valeur de la dernière clé est considérée lorsque des clés en double sont trouvées dans un JSON.


0

En C # si vous désérialisez en un Dictionary<string, string>il faut la dernière paire de valeurs clés:

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

si vous essayez de désérialiser

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

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

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

vous obtenez une Newtonsoft.Json.JsonSerializationExceptionexception.


2
je suppose que c'est ce que la plupart (sinon toutes) les implémentations font, mais cela ne répond pas à ma question s'il est valide à partir de la spécification de JSON.
clamp

@svidgen: Ce n'est même pas l'implémentation de Microsoft ... c'est une bibliothèque tierce.
BoltClock

@BoltClock Ah, touche.
svidgen
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.