JSON语法是否允许对象中的重复键?

这是有效的JSON?

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

http://jsonlint.com/说是的。

http://www.json.org/并没有说任何关于被禁止的内容。

但显然这没有多大意义,是吗? 大多数的实现可能使用哈希表,所以它被重写无论如何。

从标准(p。ii) :

预计其他标准将参考这个标准,严格遵守JSON文本格式,同时对各种编码细节施加限制。 这些标准可能需要特定的行为。 JSON本身没有指定行为。

在标准(第2页)中还有一个JSON对象的规范:

对象结构被表示为一对围绕零个或多个名称/值对的大括号标记。 名称是一个字符串。 每个名称后跟一个单独的冒号标记,将名称与值分开。 一个逗号令牌将一个值与以下名称分开。

JSON对象图

它没有提到任何重复密钥无效或有效,所以根据规范,我将安全地假设这意味着它们被允许。

大多数JSON库的实现接受与标准不冲突的重复键,因为第一个引号。

这里有两个与C ++标准库相关的例子。 当将一些JSON对象反序列化成std::map时,拒绝重复键是有意义的。 但是当将一些JSON对象反序列化成一个std::multimap时,接受重复键是正常的。

简短的回答:是的,但不推荐。
长答案:这取决于你所说的有效…

JSON数据交换格式 (ECMA-404)没有说明重复名称(键)的任何内容。

但是, JavaScript对象表示法(JSON)数据交换格式 (RFC7159)说:

对象内的名字应该是唯一的。

在这种情况下必须按照RFC 2119的规定进行理解

应该这个词,或者是“推荐”这个形容词,意思是在特定的情况下可能存在一些无效的理由来忽略某个特定的项目,但是在选择不同的课程之前,必须理解和仔细权衡全部的含义。

RFC 7159解释了为什么独特的名称(键)是好的:

名称都是唯一的对象在某种意义上是可互操作的
接收该对象的所有软件实现将同意名称 – 值映射。 当一个对象中的名字不是
独特的,接收这样的对象的软件的行为是
不可预料的。 许多实现报告了姓氏/值对
只要。 其他实现报告错误或无法解析
对象,一些实现报告所有的名称/值对,
包括重复。

已经观察到JSON解析库在调用软件时是否使对象成员的顺序可见是不同的。 其行为不依赖于成员的实现
排序将是互操作的,他们不会
受这些差异的影响。

尝试使用Douglas Crockford (JSON的创建者)的Java实现来解析具有重复名称的字符串会导致一个异常:

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

有两个文件指定JSON格式:

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

从第一个文件接受的答案引用。 我认为第一个文件更清楚,但第二个文件更详细。

第二个文件说:

  1. 对象

    对象结构被表示为围绕零个或多个名称/值对(或成员)的一对大括号。 名称是一个字符串。 每个名称后面都有一个冒号,将名称与值分开。 一个逗号与下面的名字分开一个值。 对象内的名字应该是唯一的。

所以不要有重复的名字,但不鼓励。

JSON规范说:

一个对象是一组无名的名称/值对。

这里的重要部分是“无序的”:它意味着键的唯一性,因为唯一可以用来引用特定的键是它的关键。

另外,大多数JSON库都会将JSON对象反序列化为哈希映射/字典,其中密钥是唯一的。 当您使用重复键反序列化JSON对象时,会发生什么情况取决于库:在大多数情况下,您将得到一个错误,或者只会考虑每个重复键的最后一个值。

例如,在Python中, json.loads('{"a": 1, "a": 2}')返回{"a": 2}

在处理接受XML和JSON的API时,遇到了类似的问题,但没有记录如何处理接受的JSON中的重复键。

以下是示例JSON的有效XML表示形式:

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

当这被转换成JSON时,你会得到以下结果:

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

处理你可能称之为重复键的语言的自然映射可以作为这里潜在的最佳实践参考。

希望帮助别人!

要求目的,有不同的答案:

使用JSON序列化对象(JavaScriptObjectNotation),每个字典元素映射到一个单独的对象属性,因此定义相同属性的值的不同条目没有意义。

不过,我从一个非常具体的用例中得到了同样的问题:编写用于API测试的JSON示例,我想知道如何在不打破可用性的情况下将注释添加到我们的JSON文件中。 JSON规范不知道评论,所以我想出了一个非常简单的方法:

使用重复键来评论我们的JSON样本 。 例:

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

我们正在使用的JSON序列化程序对这些“REMARK”重复项没有问题,我们的应用程序代码完全忽略了这个小小的开销。

因此,即使应用程序层没有任何意义,这些重复项为我们提供了一个有价值的解决方法,可以在不影响JSON可用性的情况下为我们的测试样本添加注释。

应该是唯一的并不意味着必须是唯一的。 然而,如上所述,一些解析器会失败,而其他解析器只会使用解析的最后一个值。 然而,如果规范被清理了一点,以允许重复,那么我可以看到一个用途,你可能有一个事件处理程序,将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> 

我可以看到这个问题背后的推理,但是现在呢,我不会相信它。

它没有在ECMA JSON标准中定义。 一般来说,标准缺乏定义就意味着“不要指望它在任何地方都以同样的方式工作”。

如果你是一个赌徒,“许多”JSON引擎将允许重复,只是使用最后指定的值。 这个:

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

变成这样:

 Object {a: 3, b: 2} 

但是如果你不是一个赌徒, 不要指望它!

根据RFC-7159,互联网工程任务组(IETF)发布的JSON现行标准规定:“对象内的名称应该是唯一的”。 然而,根据定义IETF文件中使用的术语的RFC-2119,“应该”实际上是指“……在特定情况下可能存在忽略某个特定项目的正当理由,但是必须理解和在选择不同的课程之前仔细权衡。“ 这基本上意味着,虽然建议使用唯一的密钥,但这不是必须的。 我们可以在JSON对象中重复键,它仍然是有效的。

从实际应用中,我发现当在JSON中找到重复键时,会考虑最后一个键的值。

在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异常。

标准确实这样说:

程序设计语言是否支持对象有很大差异,如果是的话,对象提供什么样的特性和约束。 目标系统的模型可能会大相径庭,并在不断发展。 JSON反而为表示名称/值对的集合提供了一个简单的符号。 大多数编程语言将具有一些用于表示这样的集合的特征,这些集合可以通过诸如记录,结构,字典,映射,散列或对象之类的名称来进行。

这个bug至少在node.js中。 此代码在node.js中成功

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