这是有效的json吗?
{
"a" : "x",
"a" : "y"
}
http://jsonlint.com/表示同意。
http://www.json.org/没有说什么被禁止。
但这显然没有多大意义,对吗?大多数实现可能使用哈希表,因此无论如何都将其覆盖。
这是有效的json吗?
{
"a" : "x",
"a" : "y"
}
http://jsonlint.com/表示同意。
http://www.json.org/没有说什么被禁止。
但这显然没有多大意义,对吗?大多数实现可能使用哈希表,因此无论如何都将其覆盖。
Answers:
从标准(第ii页):
预计其他标准将严格遵循JSON文本格式,同时对各种编码详细信息施加限制,以引用此标准。此类标准可能需要特定的行为。JSON本身未指定任何行为。
在标准(第2页)中,进一步介绍了JSON对象的规范:
对象结构表示为一对大括号标记,它们围绕零个或多个名称/值对。名称是一个字符串。每个名称后都有一个冒号,将名称与值分隔开。单个逗号标记将值与后面的名称分开。
它没有提及重复密钥无效或有效,因此根据规范,我可以放心地认为这意味着它们是允许的。
由于首引号,大多数JSON库实现不接受重复键并不与标准冲突。
这是与C ++标准库相关的两个示例。将某些JSON对象反序列化为时std::map
,拒绝重复的键是有意义的。但是,当将某些JSON对象反序列化为a时std::multimap
,可以像往常一样接受重复的键。
std::multimap
我刚刚添加的示例。可以使用可能重复的密钥将其序列化为JSON对象。
{"a":1,"a":2}
是一组两个不同的键/值对。实际上,甚至{"a":1,"a":1}
可以将其视为一组恰好只有一个元素的键/值对。重复它的事实可以被认为只是一种语法怪癖。更好的定义是“对象是从字符串(名称)到值的部分函数”。
简短的答案:是,但不建议这样做。
长答案:取决于您所说的有效...
ECMA-404 “ JSON数据交换语法”未提及重复的名称(键)。
但是,RFC 8259 “ JavaScript对象符号(JSON)数据交换格式”表示:
对象中的名称应唯一。
在这种情况下应该作为规定必须理解BCP 14:
应该使用这个词,或形容词“推荐”,这意味着在特定情况下可能存在忽略某个特定项目的正当理由,但是在选择其他方法之前,必须理解并仔细权衡所有含义。
RFC 8259解释了为什么唯一名称(键)很好:
从名称接收到的所有软件实现都将在名称-值映射上达成一致的意义上来说,名称都是唯一的对象是可以互操作的。当对象中的名称不是唯一的时,接收到该对象的软件的行为是不可预测的。许多实现仅报告姓/值对。其他实现报告错误或无法解析对象,某些实现报告所有名称/值对,包括重复项。
另外,正如Serguei在评论中指出的那样:ECMA-262 “ECMAScript®语言规范”的内容如下:
如果一个对象中有重复的名称字符串,则相同键的词法先前值应被覆盖。
换句话说,最终值就是胜利。
Douglas Crockford(JSON的创建者)使用Java实现尝试解析具有重复名称的字符串会导致异常:
org.json.JSONException: Duplicate key "status" at
org.json.JSONObject.putOnce(JSONObject.java:1076)
d8 -e 'x={"a":1,"a":2}; print(x.a);'
这将打印2
有2个文档指定JSON格式:
接受的答案引用第一个文件。我认为第一个文件更清晰,但是第二个文件包含更多细节。
第二份文件说:
对象
对象结构表示为一对大括号,包围着零个或多个名称/值对(或成员)。名称是一个字符串。每个名称后都有一个冒号,将名称与值分开。单个逗号将值与后面的名称分开。 对象中的名称应唯一。
因此,不禁止使用重复的名称,但是不建议使用。
JSON规范说:
对象是名称/值对的无序集合。
这里的重要部分是“无序的”:它暗示了密钥的唯一性,因为唯一可以用来指代特定对的就是密钥。
另外,大多数JSON库会将JSON对象反序列化为哈希映射/字典,其中键是唯一的。使用重复键反序列化JSON对象时会发生什么情况取决于库:在大多数情况下,您会得到一个错误,或者仅将每个重复键的最后一个值考虑在内。
例如,在Python中,json.loads('{"a": 1, "a": 2}')
返回{"a": 2}
。
应该是唯一的并不意味着必须是唯一的。但是,如上所述,某些解析器将失败,而其他解析器将仅使用解析的最后一个值。但是,如果对规范进行了一些清理以允许重复,那么我可以看到您可以在其中使用事件处理程序将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依赖于字典中键的顺序,因此您所听说的(有序字典)并不是闻所未闻的。您只需要一个专门的解析器。
出于目的,有不同的答案:
使用JSON序列化对象(JavaScriptObjectNotation),每个字典元素都映射到单个对象属性,因此为相同属性定义值的不同条目没有意义。
但是,我从一个非常特定的用例中遇到了同样的问题:编写用于API测试的JSON示例,我想知道如何在不破坏可用性的情况下向我们的JSON文件添加注释。JSON规范不知道注释,因此我想出了一种非常简单的方法:
要使用重复键来注释我们的JSON示例。例:
{
"property1" : "value1", "REMARK" : "... prop1 controls ...",
"property2" : "value2", "REMARK" : "... value2 raises an exception ...",
}
我们正在使用的JSON序列化程序对于这些“ REMARK”重复项没有任何问题,我们的应用程序代码只是忽略了这一小开销。
因此,即使在应用程序层上没有意义,这些重复项对我们来说也提供了一种宝贵的解决方法,可以在不破坏JSON可用性的情况下向我们的测试示例添加注释。
发布和回答,因为关于标准存在很多过时的想法和混乱。截至2017年12月,有两个相互竞争的标准:
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 )中专门定义,
- 应该使用这个词,或形容词“推荐”,这意味着在特定情况下可能存在忽略特定项目的正当理由,但是在选择其他方法之前,必须理解并仔细权衡所有含义。
ECMA-404:
“ JSON语法不对用作名称的字符串施加任何限制,不要求名称字符串是唯一的,并且不对名称/值对的排序赋予任何意义。”
因此,无论如何切片,它在语法上都是有效的JSON。
RFC 8259中给出唯一密钥建议的原因是,
从名称接收到的所有软件实现都将在名称-值映射上达成一致的意义上来说,名称都是唯一的对象是可以互操作的。当对象中的名称不是唯一的时,接收到该对象的软件的行为是不可预测的。许多实现仅报告姓/值对。其他实现报告错误或无法解析对象,某些实现报告所有名称/值对,包括重复项。
换句话说,从RFC 8259的角度来看,它是有效的,但是您的解析器可能会阻塞并且无法保证哪个值(如果有)将与该键配对。从ECMA-404的观点(我个人认为是权威)来看,这是有效的。对我来说,这意味着任何拒绝解析的解析器都是损坏的。它至少应根据这两个标准进行解析。但是,无论如何,如何将其变成您的首选本机对象,无论是否具有唯一键,都完全取决于环境和情况,并且这些都不是标准的开始。
ECMA JSON标准中未定义它。通常来说,标准中缺乏定义意味着“不要在任何地方都以相同的方式来工作”。
如果您是一名赌徒,那么“许多” JSON引擎将允许重复并且仅使用最后指定的值。这个:
var o = {"a": 1, "b": 2, "a": 3}
变成这个:
Object {a: 3, b: 2}
但是,如果您不是赌徒,那就不要指望它!
该标准确实说明了这一点:
编程语言在是否支持对象以及是否支持对象方面存在很大差异。对象系统的模型可能大相径庭,并且还在不断发展。JSON提供了一种简单的表示法来表示名称/值对的集合。大多数编程语言都具有一些表示此类集合的功能,可以按记录,结构,字典,映射,哈希或对象之类的名称命名。
该错误至少存在于node.js中。此代码在node.js中成功。
try {
var json = {"name":"n","name":"v"};
console.log(json); // outputs { name: 'v' }
} catch (e) {
console.log(e);
}
在C#中,如果您反序列化为a,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
例外。
Dictionary<string, string>