Czy składnia JSON pozwala na duplikowanie kluczy w obiekcie?

205

Czy to ważny Json?

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

http://jsonlint.com/ mówi tak.

http://www.json.org/ nie mówi nic o zakazie.

Ale oczywiście nie ma to większego sensu, prawda? Większość implementacji prawdopodobnie korzysta z tablicy mieszającej, więc i tak jest ona zastępowana.

Zacisk
źródło
1
Json.NET w C # usuwa pierwszą parę kluczy, jeśli deserializuje się doDictionary<string, string>
Sam Leach
Na wypadek, gdyby ktoś przybył tutaj z nadzieją na znalezienie podwójnych wartości w ciągach JSON, sprawdź bezpłatny internetowy walidator json
Pepijn Olivier
jsonlint.com mówi tak. nie robi tego, usuwa wszystkie oprócz ostatniej pary klucz-wartość, a następnie sprawdza poprawność, co czyni ją poprawną
Tim
7
Potem standard jest łamany
Brad Thomas,
1
Użyłem nazwy klucza „-” jako komentatora, a wartością jest pojedynczy ciąg znaków jako komentarz. Mam więc nadzieję, że żaden parser nie będzie na to narzekał.
Lothar

Odpowiedzi:

126

Ze standardu (p. Ii) :

Oczekuje się, że inne standardy będą odnosić się do tego, ściśle przestrzegając formatu tekstowego JSON, nakładając ograniczenia na różne szczegóły kodowania. Takie standardy mogą wymagać określonych zachowań. Sam JSON nie określa żadnego zachowania.

W dalszej części standardu (s. 2) specyfikacja obiektu JSON:

Struktura obiektu jest reprezentowana jako para nawiasów klamrowych otaczających zero lub więcej par nazwa / wartość. Nazwa to ciąg znaków. Pojedynczy token dwukropka podąża za każdą nazwą, oddzielając nazwę od wartości. Pojedynczy token przecinka oddziela wartość od następującej nazwy.

Schemat obiektu JSON

Nie wspomina o tym, że zduplikowane klucze są nieprawidłowe lub prawidłowe, więc zgodnie ze specyfikacją bezpiecznie zakładam, że oznacza to, że są dozwolone.

To, że większość implementacji bibliotek JSON nie akceptuje duplikatów kluczy, nie powoduje konfliktu ze standardem z powodu pierwszego cytatu.

Oto dwa przykłady związane ze standardową biblioteką C ++. Podczas deserializacji niektórych obiektów JSON w std::mapsensowne byłoby odrzucenie duplikatów kluczy. Ale podczas deserializacji jakiegoś obiektu JSON w std::multimapsensowne byłoby normalne akceptowanie zduplikowanych kluczy.

Tarcze Tymoteusza
źródło
5
Myślę, że mogę zaakceptować to jako odpowiedź, chociaż podoba mi się wzmianka @PatrickGoley, że na json.org nazywa się to zestawem kluczy / par-wartości, co implikuje unikalność, co oznaczałoby, że jest niepoprawna.
zacisk
8
@clamp json.org nie jest standardem i, o ile wiem, nie jest prowadzony przez Emca International. json.org wydaje się prezentowany anonimowo. To specyfikacja: ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf Co mówi na json.org nie ma znaczenia.
Timothy Shields
5
@clamp Rozważ std::multimapprzykład, który właśnie dodałem. Może być serializowany jako obiekt JSON z potencjalnie zduplikowanymi kluczami.
Timothy Shields
1
@clamp będący zestawem par klucz / wartość nie wyklucza duplikowania nazw. {"a":1,"a":2}to zestaw dwóch odrębnych par klucz / wartość. Rzeczywiście, nawet {"a":1,"a":1}można go traktować jako zestaw par klucz / wartość, który ma tylko jeden element. Powtarzanie tego można traktować jako dziwactwo składniowe. Lepszą definicją byłoby: „Obiekt jest funkcją częściową od ciągów (nazw) do wartości”.
Marcelo Cantos,
2
@TimothyShields A ten standard, do którego się odnosisz, mówi: „Składnia JSON nie nakłada żadnych ograniczeń na ciągi znaków używane jako nazwy, nie wymaga, aby ciągi nazw były unikalne i nie przypisywał żadnego znaczenia porządkowi par nazwa-wartość”
Charles
135

Krótka odpowiedź: tak, ale nie jest zalecana.
Długa odpowiedź: zależy od tego, co nazywacie ważnym ...


ECMA-404 „Składnia wymiany danych JSON” nie mówi nic o zduplikowanych nazwach (kluczach).


Jednak RFC 8259 „Format wymiany danych JavaScript (JSON)” mówi:

Nazwy w obiekcie POWINNY być unikalne.

W tym kontekście NALEŻY rozumieć, jak określono w BCP 14 :

POWINIEN To słowo lub przymiotnik „ZALECANE” oznaczają, że mogą istnieć uzasadnione powody, aby w określonych okolicznościach zignorować dany element, ale pełne implikacje należy zrozumieć i dokładnie rozważyć przed wyborem innego kursu.


RFC 8259 wyjaśnia, dlaczego unikalne nazwy (klucze) są dobre:

Obiekt, którego nazwy są unikalne, jest interoperacyjny w tym sensie, że wszystkie implementacje oprogramowania odbierające ten obiekt zgadzają się na odwzorowania nazwa-wartość. Gdy nazwy w obiekcie nie są unikalne, zachowanie oprogramowania, które odbiera taki obiekt, jest nieprzewidywalne. Wiele implementacji zgłasza tylko parę nazwisko / wartość. Inne implementacje zgłaszają błąd lub nie analizują obiektu, a niektóre implementacje zgłaszają wszystkie pary nazwa / wartość, w tym duplikaty.



Ponadto, jak zauważył Serguei w komentarzach: ECMA-262 „Specyfikacja języka ECMAScript®” brzmi:

W przypadku, gdy w obiekcie znajdują się zduplikowane ciągi nazw, leksykalnie poprzedzające wartości dla tego samego klucza zostaną zastąpione.

Innymi słowy, ostatnia wartość wygrywa.


Próba przetworzenia ciągu o zduplikowanych nazwach z implementacją Java przez Douglasa Crockforda (twórcę JSON) powoduje wyjątek :

org.json.JSONException: Duplicate key "status"  at
org.json.JSONObject.putOnce(JSONObject.java:1076)
użytkownik454322
źródło
1
JSON powinien być poprawnym językiem JavaScript, więc należy sprawdzić, czy zduplikowane klucze są poprawnymi literami JS. Wydaje się, że V8 je akceptuje: d8 -e 'x={"a":1,"a":2}; print(x.a);'Drukuje 2.
Ben Crowell
5
Również ECMA-262 spec JSON.parse()wyraźnie mówi In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.(innymi słowy last value-wins).
Serguei,
4
@BenCrowell: O ile mi wiadomo, JSON nie powinien być poprawnym JavaScriptem i są przypadki, w których tak nie jest, patrz timelessrepo.com/json-isnt-a-javascript-subset . To powiedziawszy, było oczywiście mocno zainspirowane JavaScriptem (nawet tak mówi specyfikacja JSON).
Simon Touchtech,
2
Warto zauważyć, że w przypadku korzystania z „trybu ścisłego” javascript, jeśli istnieją dwa identyczne klucze, chrome użyje drugiej pary klucz-wartość i zignoruje pierwszą. IE11 zgłosi wyjątek.
Shahar,
18

Istnieją 2 dokumenty określające format JSON:

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

Przyjęta odpowiedź przytacza pierwszy dokument. Myślę, że pierwszy dokument jest bardziej przejrzysty, ale drugi zawiera więcej szczegółów.

Drugi dokument mówi:

  1. Obiekty

    Struktura obiektu jest reprezentowana jako para nawiasów klamrowych otaczających zero lub więcej par nazwa / wartość (lub członków). Nazwa to ciąg znaków. Po każdej nazwie występuje pojedynczy dwukropek, oddzielający nazwę od wartości. Pojedynczy przecinek oddziela wartość od następującej nazwy. Nazwy w obiekcie POWINNY być unikalne.

Nie jest więc zabronione posiadanie zduplikowanej nazwy, ale jest odradzane.

toongeorges
źródło
10

Podobne pytanie natrafiłem na interfejs API, który akceptuje zarówno XML, jak i JSON, ale nie dokumentuje, w jaki sposób poradziłby sobie z tym, czego można oczekiwać od duplikatów kluczy w JSON.

Poniżej przedstawiono poprawną reprezentację XML przykładowego JSON:

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

Po przekonwertowaniu na JSON otrzymujesz:

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

Naturalne odwzorowanie z języka, który obsługuje to, co możesz nazwać duplikatami kluczy na inny, może służyć jako potencjalne źródło najlepszych praktyk.

Mam nadzieję, że komuś pomoże!

darren
źródło
5

Specyfikacja JSON mówi:

Obiekt to nieuporządkowany zestaw par nazwa / wartość.

Ważną częścią jest tutaj „nieuporządkowany”: implikuje wyjątkowość kluczy, ponieważ jedyną rzeczą, której można użyć w odniesieniu do konkretnej pary, jest jej klucz.

Ponadto większość bibliotek JSON usunie z szeregów obiekty JSON w postaci map haszowania / słowników, w których klucze są unikalne. Co stanie się, gdy deserializujesz obiekt JSON ze zduplikowanymi kluczami, zależy od biblioteki: w większości przypadków albo pojawi się błąd, albo tylko ostatnia wartość dla każdego zduplikowanego klucza zostanie wzięta pod uwagę.

Na przykład w Pythonie json.loads('{"a": 1, "a": 2}')zwraca {"a": 2}.

Max Noel
źródło
23
czy nieuporządkowana oznacza wyjątkowość? Myślę, że set jest tutaj słowem operacyjnym
Patrick Goley
8
Nieuporządkowana kolekcja kolorów: niebieski, zielony, zielony, niebieski, czerwony, niebieski, zielony - ma duplikaty.
Timothy Shields
5
Cytowane przez Ciebie wyrażenie tekstowe „Obiekt to nieuporządkowany zestaw par nazwa / wartość” nie pojawia się w specyfikacji JSON ...
Timothy Shields
6
Widzę teraz, że cytowałeś json.org. Jest „zbliżony” do oficjalnego, ale nie jest to specyfikacja. Na górze strony znajduje się link do specyfikacji, który jest powtarzany dosłownie na json.org. Podczas wyszukiwania specyfikacji słowo „nieuporządkowany” nie pojawia się, a słowo „zestaw” pojawia się tylko w kontekstach niezwiązanych z obiektami JSON.
Timothy Shields
5
Zauważ, że jest napisane „nieuporządkowany zestaw par nazwa / wartość ”, a nie pary. Oznacza to, że { (a,b), (a,c) } jest unikatowy zestaw. Więc technicznie zgodnie z definicją json.org {"a":1,"a":2}jest poprawna, ale {"a":1,"a":2,"a":1}nie jest. Należy również zauważyć, że ECMA-404 (aktualny standard) unika słowa „set”:An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.
Serguei
3

POWINNY być unikalne, nie oznacza, że ​​MUSI być wyjątkowe. Jednak, jak powiedziano, niektóre parsery zawiodą, a inne wykorzystają tylko ostatnią przeanalizowaną wartość. Jeśli jednak specyfikacja została nieco wyczyszczona, aby umożliwić tworzenie duplikatów, mógłbym zobaczyć zastosowanie, w którym możesz mieć moduł obsługi zdarzeń, który przekształca JSON na HTML lub inny format ... w takich przypadkach byłoby całkowicie poprawne przeanalizuj JSON i utwórz inny format dokumentu ...

[
  "div":
  {
    "p":"hello",
    "p":"universe"
  }
  "div":
  {
    "h1":"Heading 1",
    "p":"another paragraph"
  }
]

może następnie łatwo parsować na przykład do HTML

<body>
 <div>
  <p>hello</p>
  <p>universe</p>
 </div>
 <div>
  <h1>Heading 1</h1>
  <p>another paragraph</p>
 </div>
</body>

Widzę uzasadnienie pytania, ale w obecnej formie ... nie ufałbym temu.

Colin Saxton
źródło
W tablicy pierwszego przykładu brakuje przecinka. Jest to również niespójne z samym sobą. Jeśli zamierzasz używać słownika jako uporządkowanej kolekcji, twoja zewnętrzna tablica powinna być również obiektem. Tj {"div":{"p":"hello","p":"universe"}, "div":{"h1":"Heading 1","p":"another paragraph"}}. Teraz wiele osób i struktur traktuje obiekty JSON jako nieuporządkowane słowniki, ale JavaScript i np. API MongoDB polegają na porządkowaniu kluczy w słownikach, więc to, co sugerujesz (uporządkowane słowniki), nie jest niespotykane. Potrzebujesz tylko specjalistycznego parsera.
binki
2

Pytając o cel, istnieją różne odpowiedzi:

Używając JSON do serializacji obiektów (JavaScriptObjectNotation), każdy element słownika jest mapowany na indywidualną właściwość obiektu, więc różne wpisy definiujące wartość dla tej samej właściwości nie mają znaczenia.

Jednak trafiłem na to samo pytanie z bardzo konkretnego przypadku użycia: pisząc próbki JSON do testowania API, zastanawiałem się, jak dodać komentarze do naszego pliku JSON, nie przerywając użyteczności. Specyfikacja JSON nie zna komentarzy, więc wpadłem na bardzo proste podejście:

Aby użyć duplikatów kluczy, aby skomentować nasze próbki JSON . Przykład:

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

Serializatory JSON, których używamy, nie mają problemów z tymi duplikatami „UWAGA”, a nasz kod aplikacji po prostu ignoruje ten niewielki narzut.

Tak więc, mimo że nie ma żadnego znaczenia w warstwie aplikacji, te duplikaty stanowią dla nas cenne obejście pozwalające dodawać komentarze do naszych próbek testowych bez przerywania użyteczności JSON.

aknoepfel
źródło
To jest zły pomysł. Dołączając duplikaty kluczy, nawet jeśli nie musisz w nich czytać danych, polegasz na niezdefiniowanym zachowaniu. Niektóre parsery, takie jak parser JSON-java Crockforda, zgłaszają wyjątek i odmawiają analizy danych.
Richard Smith
Właściwie działa idealnie w naszym środowisku, więc spełniam moje potrzeby, mimo że zgadzam się z tobą, że jest to coś
nietypowego
@RichardSmith Powiedziałbym, że parsery i nowsze specyfikacje ES zdefiniowały zachowanie.
binki
2

Publikowanie i odpowiadanie, ponieważ istnieje wiele nieaktualnych pomysłów i niejasności dotyczące standardów. Od grudnia 2017 r. Istnieją dwa konkurujące ze sobą standardy:

RFC 8259 - https://tools.ietf.org/html/rfc8259

ECMA-404 - http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf

json.org sugeruje ECMA-404 jest standard, ale ta strona nie wydaje się być autorytetem. Chociaż uważam, że sprawiedliwe jest uznawanie ECMA za autorytet, ważne jest tutaj, jedyna różnica między standardami (dotycząca unikatowych kluczy) polega na tym, że RFC 8259 mówi, że klucze powinny być unikalne, a ECMA-404 mówi, że nie muszą być wyjątkowy.

RFC-8259:

„Nazwy w obiekcie POWINNY być unikalne”.

Słowo „powinien” we wszystkich takich wersjach ma znaczenie w świecie RFC, które jest szczegółowo zdefiniowane w innym standardzie (BCP 14, RFC 2119 - https://tools.ietf.org/html/rfc2119 ), ponieważ:

  1. POWINIEN To słowo lub przymiotnik „ZALECANE” oznaczają, że w pewnych okolicznościach mogą istnieć uzasadnione powody, aby zignorować dany element, ale należy w pełni zrozumieć i dokładnie rozważyć wszystkie implikacje przed wyborem innego kursu.

ECMA-404:

„Składnia JSON nie nakłada żadnych ograniczeń na ciągi używane jako nazwy, nie wymaga, aby ciągi nazw były unikalne i nie przypisywał żadnego znaczenia porządkowi par nazwa / wartość”.

Tak więc, bez względu na to, jak go pokroisz , jest on poprawny pod względem składniowym JSON .

Powodem podania unikalnej kluczowej rekomendacji w RFC 8259 jest:

Obiekt, którego nazwy są unikalne, jest interoperacyjny w tym sensie, że wszystkie implementacje oprogramowania odbierające ten obiekt zgadzają się na odwzorowania nazwa-wartość. Gdy nazwy w obiekcie nie są unikalne, zachowanie oprogramowania, które odbiera taki obiekt, jest nieprzewidywalne. Wiele implementacji zgłasza tylko parę nazwisko / wartość. Inne implementacje zgłaszają błąd lub nie analizują obiektu, a niektóre implementacje zgłaszają wszystkie pary nazwa / wartość, w tym duplikaty.

Innymi słowy, z punktu widzenia RFC 8259 jest on poprawny, ale twój parser może się nie poddawać i nie ma obietnicy, która wartość, jeśli w ogóle, zostanie sparowana z tym kluczem. Z punktu widzenia ECMA-404 (który osobiście uważam za autorytet) jest to ważna kropka. Dla mnie oznacza to, że każdy analizator składni, który odmawia jego analizy, jest uszkodzony. Powinien przynajmniej parsować zgodnie z obydwoma standardami. Jednak sposób, w jaki zmienia się w wybrany obiekt natywny, jest, w każdym razie, unikalnymi kluczami, całkowicie zależnymi od środowiska i sytuacji, i na początku żaden z nich nie jest w standardzie.

xthr33
źródło
json.org faktycznie wyprzedza standaryzację ECMA. Sądzę, że tak naprawdę został skonfigurowany przez samego Crockforda (dlatego ma bezwstydną wtyczkę do swojej książki). W tym momencie był to autorytet JSON.
maks.
1

Nie jest to zdefiniowane w standardzie ECMA JSON . I ogólnie mówiąc, brak definicji w standardzie oznacza: „Nie licz na to, że działa to tak samo wszędzie”.

Jeśli jesteś hazardzistą, „wiele” silników JSON pozwoli na powielanie i po prostu użyje ostatniej podanej wartości. To:

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

Staje się to:

Object {a: 3, b: 2}

Ale jeśli nie jesteś hazardzistą, nie licz na to!

svidgen
źródło
1

Norma mówi:

Języki programowania różnią się znacznie w zależności od tego, czy obsługują obiekty, a jeśli tak, jakie cechy i ograniczenia oferują te obiekty. Modele systemów obiektowych mogą być bardzo rozbieżne i wciąż ewoluują. Zamiast tego JSON zapewnia prosty zapis do wyrażania kolekcji par nazwa / wartość. Większość języków programowania będzie miała pewną funkcję do reprezentowania takich kolekcji, które mogą nosić nazwy takie jak record, struct, dict, map, hash lub object.

Błąd znajduje się co najmniej w pliku node.js. Ten kod kończy się pomyślnie w node.js.

try {
     var json = {"name":"n","name":"v"};
     console.log(json); // outputs { name: 'v' }
} catch (e) {
     console.log(e);
}
John Carlson
źródło
1
To nie jest błąd, a cytowana sekcja wyjaśnia, dlaczego tak nie jest: różne języki zachowują się inaczej, a parsery JSON zrobią to, co najbardziej naturalne dla tego języka. W każdym razie ta odpowiedź nie dodaje niczego, czego użytkownik454322 nie powiedział wcześniej.
Richard Smith
1

Według RFC-7159, obecny standard JSON opublikowany przez Internet Engineering Task Force (IETF), stwierdza: „Nazwy w obiekcie POWINNY być unikalne”. Jednak zgodnie z RFC-2119, która definiuje terminologię stosowaną w dokumentach IETF, słowo „powinno” w rzeczywistości oznacza „… mogą istnieć uzasadnione powody w szczególnych okolicznościach, aby zignorować określoną pozycję, ale należy w pełni zrozumieć i dokładnie zważony przed wyborem innego kursu. ” Zasadniczo oznacza to, że chociaż unikatowe klucze są zalecane, nie jest to konieczne. Możemy mieć zduplikowane klucze w obiekcie JSON i nadal byłby ważny.

Od praktycznego zastosowania widziałem, że wartość z ostatniego klucza jest brana pod uwagę, gdy duplikaty kluczy są znalezione w JSON.

Navaneetha
źródło
0

W C #, jeśli deserializujesz do a Dictionary<string, string>, bierze ostatnią parę klucz-wartość:

string json = @"{""a"": ""x"", ""a"": ""y""}";
var d = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
// { "a" : "y" }

jeśli spróbujesz deserializować do

class Foo
{
    [JsonProperty("a")]
    public string Bar { get; set; }

    [JsonProperty("a")]
    public string Baz { get; set; }
}

var f = JsonConvert.DeserializeObject<Foo>(json);

dostajesz Newtonsoft.Json.JsonSerializationExceptionwyjątek.

Sam Leach
źródło
2
Myślę, że to właśnie robi większość (jeśli nie wszystkie) implementacje, ale nie odpowiada na moje pytanie, czy jest zgodne ze specyfikacją JSON.
zacisk
@svidgen: To nie jest nawet implementacja Microsoftu ... to biblioteka innej firmy.
BoltClock
@BoltClock Ah, dotknąć.
svidgen