Комментарии 23
JSON это javascript object notation. Javascript регистрозависимый.Следовательно и ключи JSON объекта регистрозависимые. То что они представлены в виде строк, я думаю, роли не играет.
Это доказательство ради доказательства, скорее.
Так-то все очевидно, тем кто хоть раз работал с JSON (а это почти все программисты в вебе)
Нет, почему же.
Язык js - это стандарт
Образованный от него json - тоже подчиняется правилам стандарта.
То, что некоторые реализации игнорируют или позволяют обходить стандарт - это их прихоть, не имеющая отношения к json
Пусть и удобная.
Так что можно с уверенностью сказать - ключи в json регистрозависимые
Ваш пример не корректен. То что строки во всех ЯП всегда сохраняют регистр, это не значит что метки в JSON должны быть регистрозависимыми, одно из другого никак не вытекает.
В части XML например, в спецификации четко указано, что теги регистрозависимы, по поводу JSON такого найти не смог. Зато нашел интересную информацию: C# – Case sensitivity in JSON deserialization - "By default Newtonsoft does case insensitive JSON deserialization and System.Text.Json does case sensitive JSON deserialization". Получается кто как хочет так и делает.
https://makolyte.com/csharp-case-sensitivity-in-json-deserialization/
И кстати тут ответ на Ваш вопрос "Я не встречал языка, в котором JSON был бы регистронезависимым. Если вы такой знаете - сообщите, будет интересно."
Не имею возможности на C# проверить, к сожалению. Можете такой же пример из статьи воспроизвести?
Теория тут не особо уместна, как мне кажется. Делают как хотят, но работают с этим сторонние люди и такие детские проблемы - для банка не серьезно.
Не удивительно, что такое поведение именно в C#. Отголосок Windows, в которой имена файлов тоже регистронезависимые.
Соглашусь, но не полностью. В том же XML четко описано поведение - регистрозависимо и точка будь то Windows или Linux, а в JSON-е отсутствует требование, которое каждый трактует индивидуально. В компоненте Newtonsoft например настраиваемо, но по дефолту регистронезависимо, никто не мешает изменить.
options.PropertyNameCaseInsensitive = true;
Проверил C#. Вот так получается регистрозависимо:
using System;
using System.Text.Json;
namespace Test1
{
class DataContainer
{
public int data { get; set; }
}
class Program
{
static void Main(string[] args)
{
var c0 = JsonSerializer.Deserialize<DataContainer>("{ \"data\": 2 }");
var c1 = JsonSerializer.Deserialize<DataContainer>("{ \"Data\": 2 }");
var c2 = JsonSerializer.Deserialize<DataContainer>("{ \"DATA\": 2 }");
var c3 = JsonSerializer.Deserialize<DataContainer>("{ \"daTA\": 2 }");
Console.WriteLine("data: {0}, Data: {1}, DATA: {2}, daTA {3}", c0.data, c1.data, c2.data, c3.data);
}
}
}
Выводит:
data: 2, Data: 0, DATA: 0, daTA 0
Теперь включаем регистронезависимость:
using System;
using System.Text.Json;
namespace Test1
{
class DataContainer
{
public int data { get; set; }
}
class Program
{
static void Main(string[] args)
{
JsonSerializerOptions opt = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
};
var c0 = JsonSerializer.Deserialize<DataContainer>("{ \"data\": 2 }", opt);
var c1 = JsonSerializer.Deserialize<DataContainer>("{ \"Data\": 2 }", opt);
var c2 = JsonSerializer.Deserialize<DataContainer>("{ \"DATA\": 2 }", opt);
var c3 = JsonSerializer.Deserialize<DataContainer>("{ \"daTA\": 2 }", opt);
Console.WriteLine("data: {0}, Data: {1}, DATA: {2}, daTA {3}", c0.data, c1.data, c2.data, c3.data);
}
}
}
Выводит:
data: 2, Data: 2, DATA: 2, daTA 2
А если есть свойства, отличающиеся только регистром, а мы включаем регистронезависимость, то получим ошибку
using System;
using System.Text.Json;
namespace Test1
{
class DataContainer
{
public int data { get; set; }
public int DATA { get; set; }
}
class Program
{
static void Main(string[] args)
{
JsonSerializerOptions opt = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
};
var c0 = JsonSerializer.Deserialize<DataContainer>("{ \"data\": 2 }", opt);
var c1 = JsonSerializer.Deserialize<DataContainer>("{ \"Data\": 2 }", opt);
var c2 = JsonSerializer.Deserialize<DataContainer>("{ \"DATA\": 2 }", opt);
var c3 = JsonSerializer.Deserialize<DataContainer>("{ \"daTA\": 2 }", opt);
Console.WriteLine("data: {0}, {1}, Data: {2}, {3}, DATA: {4}, {5}, daTA {6}, {7}", c0.data, c0.DATA, c1.data, c1.DATA, c2.data, c2.DATA, c3.data, c3.DATA);
}
}
}
Кидает InvalidOperationException с текстом "The JSON property name for 'Test1.DataContainer.DATA' collides with another property."
Никакой связи. Я думаю, основная причина в различной нотации принятой в Javascript/JSON (camelCase) и C# (PascalCase). Чтобы можно было автоматически сериализировать шарповые DTO`шки
Чтобы делать разную нотацию, используется атрибут [JsonPropertyName("data")]
Найти упоминание регистрозависимости JSON в спецификации - еще более сложная задача
да ладно, это в rfc8259 описано отдельным параграфом:
8.3. String Comparison
Software implementations are typically required to test names of object members for equality. Implementations that transform the textual representation into sequences of Unicode code units and then perform the comparison numerically, code unit by code unit, are interoperable in the sense that implementations will agree in all cases on equality or inequality of two strings.
Escape-последовательности раскрываются в Unicode, а затем такие подготовленные строки бинарно сравниваются. Т.е. имена членов объектов регистрозависимы.
Отлично. А я не нашел. Спасибо :)
Справедливости ради это не относится к требованию к тегам, а лишь к сравнению строк!
Почитайте например п 8.2.
" Однако ABNF в этой спецификации разрешает имена элементов и значения строк с битовыми последовательностями, которые не могут быть представлены символами Unicode, например, "\uDEAD" (один непарный суррогат UTF-16). Такие экземпляры могут встречаться, например, при отсечке библиотекой строк UTF-16 без проверки разрыва суррогатных пар. Поведение программы, получившей текст JSON с такими значениями, не предсказуемо. "
Перевод RFC - https://www.protokols.ru/WP/wp-content/uploads/2017/12/rfc8259.pdf
Я так же прекрасно понимаю, что тут (как и всегда) действует принцип "что хочу, то и ворочу". Каждый ЯП может по своему реализовать JSON. Более того, даже разные библиотеки могут по разному парсить JSON. Но все же я не встречал регистронезависимых ключей.
Как у вас и указано "Поведение программы, получившей текст JSON с такими значениями, не предсказуемо" - как раз поэтому, мне кажется, строковые ключи - это обычные строки, а значит регистрозависимые.
RFC 8259 нормативно ссылается на ECMA-404, в котором явно определяется что:
«...The JSON syntax does not impose any restrictions on the strings used as names, does not require that name strings be unique, and does not assign any significance to the ordering of name/value pairs. These are all semantic considerations that may be defined by JSON processors or in specifications defining specific uses of JSON for data interchange....»
Т.е. могут встретиться системы обмена информацией в формате JSON, полностью соответствующие стандартам ECMA-404 и RFC 8259, но у которых имена полей объекта не зависят от регистра или вообще допускают перевод на национальные языки.
A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes. A character is represented as a single character string. A string is very much like a C or Java string.Символы d и D — это разные символы юникода.
Смотрим RFC8259:
Implementations that transform the textual representation into sequences of Unicode code units and then perform the comparison numerically, code unit by code unit, are interoperable in the sense that implementations will agree in all cases on equality or inequality of two strings.То есть напрямую рекомендуют сравнивать коды символов, которые у заглавной и строчной — разные.
Ну если так считают, то могли бы и поправить. Все равно ничего не сломается, по их мнению.
:) Можно так :)
<sarcasm>
jsonString = jsonString.toUpperCase()
Object object = deserialize
</sarcasm>
Регистрозависимые ли ключи в JSON