这是有效的json吗?

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

http://jsonlint.com/的答案是肯定的。

http://www.json.org/没有说任何关于它是禁止的。

但显然这没什么意义,不是吗? 大多数实现可能使用哈希表,所以无论如何它都会被覆盖。


当前回答

有两个文档指定JSON格式:

http://json.org/ https://www.rfc-editor.org/rfc/rfc7159

被接受的答案引用自第一个文档。我认为第一份文件更清楚,但第二份文件包含更多细节。

第二份文件说:

对象 对象结构用一对花括号表示 包围零个或多个名称/值对(或成员)。名字就是 字符串。每个名称后面都有一个冒号,分隔名称 从值。一个逗号将值与后面的字符分隔开 的名字。对象中的名称应该是唯一的。

所以不禁止使用重复的名字,但不鼓励使用。

其他回答

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

从标准(p. ii):

预计其他标准将引用此标准,严格遵循JSON文本格式,而 对各种编码细节施加限制。这种标准可能需要具体的行为。JSON 本身不指定任何行为。

在标准(第2页)中,JSON对象的规范如下:

对象结构表示为围绕零个或多个名称/值对的一对花括号标记。 名称是字符串。每个名称后面都有一个冒号标记,将名称与值分开。一个单一的 逗号标记将值与后面的名称分隔开。

它没有提到重复的键是无效的还是有效的,因此根据规范,我可以安全地假设这意味着它们是允许的。

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

下面是两个与c++标准库相关的示例。当将一些JSON对象反序列化为std::map时,拒绝重复键是有意义的。但是当将一些JSON对象反序列化为std::multimap时,正常地接受重复键是有意义的。

According to RFC-7159, the current standard for JSON published by the Internet Engineering Task Force (IETF), states "The names within an object SHOULD be unique". However, according to RFC-2119 which defines the terminology used in IETF documents, the word "should" in fact means "... there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course." What this essentially means is that while having unique keys is recommended, it is not a must. We can have duplicate keys in a JSON object, and it would still be valid.

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

标准是这么说的:

编程语言在是否支持对象和 如果是,对象提供了什么特征和约束。的 对象系统的模型可以有很大的分歧,而且还在继续如此 进化。JSON提供了一个简单的表示符号 名称/值对的集合。大多数编程语言都有 一些用于表示此类集合的特性,这些集合可以按名称命名 比如record, struct, dict, map, hash或object。

这个错误至少在node.js中。这段代码在node.js中成功了。

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

因为有很多过时的想法和对标准的困惑。截至2017年12月,有两个相互竞争的标准:

RFC 8259 - https://www.rfc-editor.org/rfc/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:

对象中的名称必须是唯一的。

像这样大写的单词“should”在RFC世界中有一个特殊的含义,在另一个标准(BCP 14, RFC 2119 - https://www.rfc-editor.org/rfc/rfc2119)中被明确定义为:

这个词或者形容词“RECOMMENDED”是这个意思吗 在特定情况下,可能存在忽视的正当理由 一个特定的项目,但必须理解全部的含义和 在选择不同的路线之前仔细权衡。

ecma - 404:

JSON语法对所使用的字符串没有任何限制 作为名称,不要求名称字符串是唯一的,也不要求 赋予名称/值对的顺序任何意义。”

无论如何分割,它都是语法上有效的JSON。

RFC 8259中给出的唯一密钥建议的原因是,

在某种意义上,名称都是唯一的对象是可互操作的 所有接收该对象的软件实现都会同意 名称-值映射。当对象中的名称不是时 唯一的,软件接收这样一个对象的行为是 不可预测的。许多实现报告姓氏/值对 只有。属性的其他实现报告错误或未能解析 对象,一些实现报告所有的名称/值对, 包括重复。

In other words, from the RFC 8259 viewpoint, it's valid but your parser may barf and there's no promise as to which, if any, value will be paired with that key. From the ECMA-404 viewpoint (which I'd personally take as the authority), it's valid, period. To me this means that any parser that refuses to parse it is broken. It should at least parse according to both of these standards. But how it gets turned into your native object of choice is, in any case, unique keys or not, completely dependent on the environment and the situation, and none of that is in the standard to begin with.