Разрешает ли синтаксис JSON дублировать ключи в объекте?
Это действительный JSON?
{
"a" : "x",
"a" : "y"
}
http://jsonlint.com/ говорит да.
http://www.json.org/ ничего не говорит о том, что это запрещено.
Но, очевидно, это не имеет особого смысла, не так ли? В большинстве реализаций, вероятно, используется хеш-таблица, поэтому она в любом случае переопределяется.
12 ответов
Ожидается, что другие стандарты будут ссылаться на этот, строго придерживаясь формата текста JSON, налагая ограничения на различные детали кодирования. Такие стандарты могут требовать определенного поведения. Сам JSON не определяет поведение.
Далее в стандарте (стр. 2) спецификация для объекта JSON:
Структура объекта представляется в виде пары фигурных скобок, окружающих ноль или более пар имя / значение. Имя - это строка. Один маркер двоеточия следует за каждым именем, отделяя имя от значения. Один токен запятой отделяет значение от следующего имени.
В нем не упоминается, что дубликаты ключей являются недействительными или допустимыми, поэтому в соответствии со спецификацией я бы смело предположил, что они разрешены.
То, что большинство реализаций библиотек JSON не принимают дубликаты ключей, не противоречит стандарту из-за первой цитаты.
Вот два примера, относящихся к стандартной библиотеке C++. При десериализации некоторого объекта JSON в std::map
было бы разумно отказаться от дубликатов ключей. Но при десериализации некоторого объекта JSON в std::multimap
было бы разумно принять дубликаты ключей как обычно.
Краткий ответ: да, но не рекомендуется.
Длинный ответ: это зависит от того, что вы называете действительным...
Формат обмена данными JSON (ECMA-404) ничего не говорит о дублированных именах (ключах).
Тем не менее формат обмена данными нотации объектов JavaScript (JSON) (RFC7159) гласит:
Имена внутри объекта ДОЛЖНЫ быть уникальными.
В этом контексте следует понимать, как указано в RFC 2119
СЛЕДУЕТ Это слово или прилагательное "РЕКОМЕНДУЕМЫЕ" означают, что могут существовать веские причины в определенных обстоятельствах игнорировать конкретный элемент, но все последствия должны быть поняты и тщательно взвешены, прежде чем выбрать другой курс.
RFC 7159 объясняет, почему уникальные имена (ключи) хороши:
Объект, все имена которого уникальны, совместим в том смысле,
что все программные реализации, получающие этот объект, согласятся с отображениями имя-значение. Когда имена внутри объекта не
уникальным, поведение программного обеспечения, которое получает такой объект
непредсказуемы. Многие реализации сообщают пару фамилия / значение
только. Другие реализации сообщают об ошибке или не могут разобрать
объект, и некоторые реализации сообщают обо всех парах имя / значение,
в том числе дубликаты.Обнаружено, что библиотеки синтаксического анализа JSON различаются в зависимости от того, делают ли они упорядочивание элементов объекта видимым для вызывающего программного обеспечения. Реализации, поведение которых не зависит от члена
порядок будет совместим в том смысле, что они не будут
пострадавших от этих различий.
Также, как отметил Сергей в комментариях: ECMA-262 "Спецификация языка ECMAScript®", гласит:
В случае если в объекте есть повторяющиеся строки имени, лексически предшествующие значения для одного и того же ключа должны быть перезаписаны.
(другими словами, последнее значение выигрывает).
Попытка синтаксического анализа строки с дублированными именами в реализации Java Дугласа Крокфорда (создателя JSON) приводит к исключению:
org.json.JSONException: Duplicate key "status" at
org.json.JSONObject.putOnce(JSONObject.java:1076)
Есть 2 документа, определяющих формат JSON:
Принятые ответы цитаты из 1-го документа. Я думаю, что первый документ более понятен, но второй содержит больше деталей.
Второй документ гласит:
Объекты
Структура объекта представляется в виде пары фигурных скобок, окружающих ноль или более пар имя / значение (или членов). Имя - это строка. После каждого имени стоит двоеточие, отделяющее имя от значения. Одна запятая отделяет значение от следующего имени. Имена внутри объекта ДОЛЖНЫ быть уникальными.
Так что не запрещено иметь повторяющееся имя, но это не рекомендуется.
Я сталкивался с подобным вопросом, когда имел дело с API, который принимает и XML, и JSON, но не документирует, как он будет обрабатывать то, что вы ожидаете от дублированных ключей в принятом JSON.
Ниже приведено правильное XML-представление вашего образца JSON:
<object>
<a>x</a>
<a>y</a>
</object>
Когда это преобразуется в JSON, вы получаете следующее:
{
"object": {
"a": [
"x",
"y"
]
}
}
Естественное сопоставление языка, который обрабатывает то, что вы могли бы назвать дублирующими ключами для другого, может послужить здесь потенциальным справочным материалом.
Надеюсь, что это помогает кому-то!
Спецификация JSON гласит:
Объект - это неупорядоченный набор пар имя / значение.
Важной частью здесь является "неупорядоченный": он подразумевает уникальность ключей, потому что единственное, что вы можете использовать для ссылки на конкретную пару, это ее ключ.
Кроме того, большинство библиотек JSON десериализуют объекты JSON в хэш-карты / словари, где ключи гарантированно уникальны. Что произойдет при десериализации объекта JSON с дубликатами ключей, зависит от библиотеки: в большинстве случаев вы либо получите ошибку, либо будет учтено только последнее значение для каждого дублирующегося ключа.
Например, в Python, json.loads('{"a": 1, "a": 2}')
возвращается {"a": 2}
,
Отправка и ответ, потому что есть много устаревших идей и путаницы в отношении стандартов. По состоянию на декабрь 2017 года существует два конкурирующих стандарта:
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 (которую я бы лично принял за авторитет), это действительно, точка. Для меня это означает, что любой синтаксический анализатор, который отказывается анализировать его, сломан. Следует хотя бы разобрать согласно обоим этим стандартам. Но то, как он превращается в ваш родной объект выбора, в любом случае, является уникальным ключом или нет, полностью зависит от среды и ситуации, и с самого начала ничего из этого не входит в стандарт.
Должен быть уникальным, не означает, что ДОЛЖЕН быть уникальным. Однако, как уже говорилось, некоторые парсеры не будут работать, а другие просто будут использовать последнее проанализированное значение. Однако, если бы спецификация была немного очищена, чтобы допускать дубликаты, я мог бы увидеть применение, где у вас может быть обработчик событий, который преобразует 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}
Но если вы не игрок, не рассчитывайте на это!
Отвечая на цель, есть разные ответы:
Используя JSON для сериализации объектов (JavaScriptObjectNotation), каждый элемент словаря отображается на отдельное свойство объекта, поэтому разные записи, определяющие значение для одного и того же свойства, не имеют смысла.
Тем не менее, я столкнулся с тем же вопросом из очень специфического варианта использования: при написании примеров JSON для тестирования API мне было интересно, как добавить комментарии в наш файл JSON, не нарушая удобство использования. Спецификация JSON не знает комментариев, поэтому я предложил очень простой подход:
Использовать дубликаты ключей для комментирования наших примеров JSON. Пример:
{
"property1" : "value1", "REMARK" : "... prop1 controls ...",
"property2" : "value2", "REMARK" : "... value2 raises an exception ...",
}
Сериализаторы JSON, которые мы используем, не имеют проблем с этими дубликатами "REMARK", и код нашего приложения просто игнорирует эти небольшие накладные расходы.
Таким образом, несмотря на то, что на прикладном уровне нет никакого смысла, эти дубликаты для нас предоставляют ценный обходной путь, позволяющий добавлять комментарии к нашим образцам тестирования, не нарушая удобство использования JSON.
Согласно RFC-7159, действующему стандарту для JSON, опубликованному Инженерной рабочей группой по Интернету (IETF), говорится: "Имена внутри объекта ДОЛЖНЫ быть уникальными". Однако, согласно RFC-2119, который определяет терминологию, используемую в документах IETF, слово "должен" фактически означает "... могут существовать веские причины в определенных обстоятельствах игнорировать конкретный элемент, но следует понимать все последствия и тщательно взвесить, прежде чем выбрать другой курс ". По сути это означает, что, хотя рекомендуется иметь уникальные ключи, это не обязательно. Мы можем иметь дубликаты ключей в объекте JSON, и он все равно будет действительным.
Из практического применения я видел, что значение из последнего ключа рассматривается, когда дубликаты ключей находятся в 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);
}
В 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
исключение.