Apakah sintaks JSON memungkinkan kunci duplikat dalam suatu objek?


205

Apakah ini json yang valid?

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

http://jsonlint.com/ mengatakan ya.

http://www.json.org/ tidak mengatakan apa-apa tentang hal itu dilarang.

Tapi jelas itu tidak masuk akal, bukan? Sebagian besar implementasi mungkin menggunakan hashtable sehingga ditimpa.


1
Json.NET C # menghapus pasangan kunci pertama jika Anda deserialise keDictionary<string, string>
Sam Leach

Jika ada yang tiba di sini berharap solusi untuk menemukan nilai duplikat dalam string JSON, periksa validator json online gratis
Pepijn Olivier

jsonlint.com mengatakan ya. tidak, itu menghapus semua kecuali pasangan kunci-nilai terakhir dan kemudian memvalidasinya, yang membuatnya valid
Tim

7
Kemudian standar dilanggar
Brad Thomas

1
Saya menggunakan nama kunci "-" sebagai komentator dan nilainya adalah garis string tunggal sebagai komentar. Jadi saya harap tidak ada parser yang akan mengeluh tentang hal itu.
Lothar

Jawaban:


126

Dari standar (p. Ii) :

Diharapkan bahwa standar lain akan merujuk pada yang satu ini, dengan benar-benar mengikuti format teks JSON, sementara memberlakukan batasan pada berbagai detail pengkodean. Standar semacam itu mungkin memerlukan perilaku tertentu. JSON sendiri tidak menetapkan perilaku.

Lebih jauh ke bawah dalam standar (hal. 2), spesifikasi untuk objek JSON:

Struktur objek direpresentasikan sebagai sepasang token braket keriting yang mengelilingi nol atau lebih pasangan nama / nilai. Nama adalah sebuah string. Token kolon tunggal mengikuti setiap nama, memisahkan nama dari nilai. Tanda koma tunggal memisahkan nilai dari nama berikut.

Diagram untuk Objek JSON

Itu tidak menyebutkan kunci duplikat menjadi tidak valid atau valid, jadi menurut spesifikasi saya akan dengan aman menganggap itu berarti mereka diizinkan.

Bahwa sebagian besar implementasi perpustakaan JSON tidak menerima kunci duplikat tidak bertentangan dengan standar, karena kutipan pertama.

Berikut adalah dua contoh yang terkait dengan pustaka standar C ++. Ketika deserializing beberapa objek JSON menjadi std::mapitu akan masuk akal untuk menolak kunci duplikat. Tetapi ketika deserializing beberapa objek JSON menjadi std::multimapitu akan masuk akal untuk menerima kunci duplikat seperti biasa.


5
Saya kira saya dapat menerima ini sebagai jawaban, meskipun saya suka menyebutkan @ Patrickrick bahwa di json.org disebut seperangkat pasangan kunci / nilai yang menyiratkan keunikan yang berarti itu tidak valid.
jepit

8
@clamp json.org bukan standar dan, sejauh yang saya tahu, tidak dijalankan oleh Emca International. json.org tampaknya disajikan secara anonim. Ini adalah yang spesifikasi: ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf Apa yang tertulis di json.org tidak relevan.
Timothy Shields

5
@ clamp Pertimbangkan std::multimapcontoh yang baru saja saya tambahkan. Ini dapat diserialisasi sebagai objek JSON dengan kunci duplikat yang berpotensi.
Timothy Shields

1
@clamp menjadi seperangkat pasangan kunci / nilai tidak menghalangi nama duplikat. {"a":1,"a":2}adalah satu set dari dua pasangan kunci / nilai yang berbeda. Memang, bahkan {"a":1,"a":1}dapat dianggap sebagai satu set pasangan kunci / nilai yang kebetulan hanya memiliki satu elemen. Fakta bahwa itu diulang dapat dianggap hanya sebagai kekhasan sintaksis. Definisi yang lebih baik adalah, "Objek adalah fungsi parsial dari string (nama) ke nilai."
Marcelo Cantos

2
@TimothyShields Dan standar yang Anda tautkan dengan mengatakan, "Sintaks JSON tidak memaksakan batasan pada string yang digunakan sebagai nama, tidak mengharuskan string nama menjadi unik, dan tidak memberikan signifikansi apa pun pada urutan pasangan nama / nilai"
Charles

135

Jawaban singkatnya: Ya tapi tidak disarankan.
Jawaban panjang: Itu tergantung pada apa yang Anda sebut valid ...


ECMA-404 "Sintaks Interchange Data JSON" tidak mengatakan apa-apa tentang nama yang digandakan (kunci).


Namun, RFC 8259 "Format Interchange Data Notasi JavaScript (JSON)" mengatakan:

Nama-nama dalam suatu objek HARUS unik.

Dalam konteks ini HARUS harus dipahami sebagaimana ditentukan dalam BCP 14 :

HARUS Kata ini, atau kata sifat "DIREKOMENDASIKAN", berarti bahwa mungkin ada alasan yang valid dalam keadaan tertentu untuk mengabaikan item tertentu, tetapi implikasi penuh harus dipahami dan ditimbang dengan hati-hati sebelum memilih kursus yang berbeda.


RFC 8259 menjelaskan mengapa nama unik (kunci) bagus:

Objek yang namanya unik semuanya dapat dioperasikan dalam arti bahwa semua implementasi perangkat lunak yang menerima objek tersebut akan menyetujui pemetaan nama-nilai. Ketika nama-nama dalam suatu objek tidak unik, perilaku perangkat lunak yang menerima objek seperti itu tidak dapat diprediksi. Banyak implementasi melaporkan hanya pasangan nama / nilai terakhir. Implementasi lain melaporkan kesalahan atau gagal menguraikan objek, dan beberapa implementasi melaporkan semua pasangan nama / nilai, termasuk duplikat.



Juga, seperti yang ditunjukkan Serguei dalam komentar: ECMA-262 "Spesifikasi Bahasa ECMAScript®", berbunyi:

Dalam kasus di mana ada string nama duplikat dalam suatu objek, nilai leksikal sebelumnya untuk kunci yang sama harus ditimpa.

Dengan kata lain, nilai terakhir menang.


Mencoba mengurai string dengan nama duplikat dengan implementasi Java oleh Douglas Crockford (pembuat JSON) menghasilkan pengecualian :

org.json.JSONException: Duplicate key "status"  at
org.json.JSONObject.putOnce(JSONObject.java:1076)

1
JSON seharusnya javascript yang valid, jadi relevan untuk memeriksa apakah kunci duplikat JS valid dalam literal. V8 tampaknya menerima mereka: d8 -e 'x={"a":1,"a":2}; print(x.a);'Ini mencetak 2.
Ben Crowell

5
Juga spesifikasi ECMA-262 untuk JSON.parse()secara eksplisit mengatakan In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.(dengan kata lain nilai terakhir menang).
Serguei

4
@BenCrowell: Sejauh yang saya tahu, JSON seharusnya tidak menjadi JavaScript yang valid dan ada beberapa kasus di mana tidak, lihat timelessrepo.com/json-isnt-a-javascript-subset . Dengan itu, tentu saja sangat terinspirasi oleh JavaScript (bahkan dikatakan demikian dalam spesifikasi JSON).
Simon Touchtech

2
Perlu dicatat bahwa ketika menggunakan "mode ketat" javascript, jika ada dua kunci yang identik, chrome akan menggunakan pasangan nilai kunci kedua dan mengabaikan yang pertama. IE11 akan memunculkan eksepsi.
Shahar

18

Ada 2 dokumen yang menentukan format JSON:

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

Kutipan yang diterima mengutip dari dokumen pertama. Saya pikir dokumen pertama lebih jelas, tetapi dokumen kedua berisi lebih banyak detail.

Dokumen ke-2 mengatakan:

  1. Benda

    Struktur objek direpresentasikan sebagai sepasang kurung keriting yang mengelilingi nol atau lebih pasangan nama / nilai (atau anggota). Nama adalah sebuah string. Satu titik dua muncul setelah setiap nama, memisahkan nama dari nilai. Satu koma memisahkan nilai dari nama berikut. Nama-nama dalam suatu objek HARUS unik.

Jadi tidak dilarang untuk memiliki nama duplikat, tetapi tidak dianjurkan.


10

Saya menemukan pertanyaan serupa ketika berhadapan dengan API yang menerima XML dan JSON, tetapi tidak mendokumentasikan bagaimana itu akan menangani apa yang Anda harapkan menjadi kunci duplikat di JSON yang diterima.

Berikut ini adalah representasi XML yang valid dari sampel JSON Anda:

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

Ketika ini dikonversi ke JSON, Anda mendapatkan yang berikut:

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

Pemetaan alami dari bahasa yang menangani apa yang Anda sebut kunci duplikat ke bahasa lain, dapat berfungsi sebagai referensi praktik terbaik potensial di sini.

Semoga itu bisa membantu seseorang!


5

Spesifikasi JSON mengatakan ini:

Objek adalah kumpulan pasangan nama / nilai yang tidak teratur.

Bagian penting di sini adalah "tidak berurutan": itu menyiratkan keunikan kunci, karena satu-satunya hal yang dapat Anda gunakan untuk merujuk ke pasangan tertentu adalah kuncinya.

Selain itu, sebagian besar lib JSON akan membatalkan deserialisasi objek JSON ke peta / kamus hash, di mana kunci dijamin unik. Apa yang terjadi ketika Anda menghapus objek JSON dengan kunci duplikat tergantung pada pustaka: dalam kebanyakan kasus, Anda akan mendapatkan kesalahan, atau hanya nilai terakhir untuk setiap kunci duplikat yang akan diperhitungkan.

Misalnya, dalam Python, json.loads('{"a": 1, "a": 2}')mengembalikan {"a": 2}.


23
apakah unordered menyiratkan keunikan? Saya pikir set adalah kata yang digunakan di sini
Patrick Goley

8
Koleksi warna yang tidak teratur: Biru, Hijau, Hijau, Biru, Merah, Biru, Hijau - Ini memiliki duplikat.
Timothy Shields

5
Frasa teks yang Anda kutip, "Objek adalah kumpulan pasangan nama / nilai yang tidak berurutan," tidak muncul dalam spesifikasi JSON ...
Timothy Shields

6
Saya mengerti sekarang bahwa Anda mengutip json.org. Ini 'dekat' dengan resmi, tetapi bukan spesifikasinya. Bagian atas halaman memiliki tautan ke spesifikasi, yang diulang kata demi kata di json.org. Jika Anda mencari spec., Kata "unordered" tidak muncul, dan kata "set" hanya muncul dalam konteks yang tidak terkait dengan objek JSON.
Timothy Shields

5
Perhatikan bahwa ia mengatakan " pasangan nama / nilai yang tidak teratur ", bukan pasangan nama. Artinya, { (a,b), (a,c) } adalah satu set yang unik. Jadi secara teknis di bawah definisi json.org {"a":1,"a":2}adalah valid tetapi {"a":1,"a":2,"a":1}tidak. Perhatikan juga bahwa ECMA-404 (standar aktual) menghindari penggunaan kata "set":An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.
Serguei

3

HARUS unik bukan berarti HARUS unik. Namun, seperti yang disebutkan, beberapa parser akan gagal dan yang lain hanya akan menggunakan nilai terakhir yang diuraikan. Namun, jika spek itu dibersihkan sedikit untuk memungkinkan duplikat maka saya bisa melihat penggunaan di mana Anda mungkin memiliki pengendali acara yang mengubah JSON menjadi HTML atau format lain ... dalam kasus seperti itu akan sangat valid untuk parsing JSON dan buat format dokumen lain ...

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

lalu bisa dengan mudah menguraikan ke html misalnya

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

Saya bisa melihat alasan di balik pertanyaan itu, tetapi seperti yang terjadi ... Saya tidak akan mempercayainya.


Array contoh pertama Anda tidak memiliki koma. Juga, itu tidak konsisten dengan dirinya sendiri. Jika Anda akan menggunakan kamus sebagai koleksi yang diurutkan, array luar Anda juga harus menjadi objek. Yaitu {"div":{"p":"hello","p":"universe"}, "div":{"h1":"Heading 1","p":"another paragraph"}},. Sekarang, banyak orang dan kerangka kerja memperlakukan objek JSON sebagai kamus yang tidak berurutan, tetapi JavaScript dan API MongoDB bergantung pada pengurutan kunci dalam kamus, jadi apa yang Anda sarankan (kamus yang dipesan) bukanlah hal yang tidak pernah terdengar. Anda hanya perlu parser khusus.
binki

2

Bertanya untuk tujuan, ada jawaban yang berbeda:

Menggunakan JSON untuk membuat objek bersambung (JavaScriptObjectNotation), setiap elemen kamus memetakan ke properti objek indivual, sehingga entri yang berbeda menentukan nilai untuk properti yang sama tidak memiliki arti.

Namun, saya menemukan pertanyaan yang sama dari kasus penggunaan yang sangat spesifik: Menulis sampel JSON untuk pengujian API, saya bertanya-tanya bagaimana cara menambahkan komentar ke file JSON kami tanpa merusak kegunaannya. Spesifikasi JSON tidak tahu komentar, jadi saya datang dengan pendekatan yang sangat sederhana:

Untuk menggunakan kunci duplikat untuk mengomentari sampel JSON kami . Contoh:

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

Serialisasi JSON yang kami gunakan tidak memiliki masalah dengan duplikat "KETERANGAN" ini dan kode aplikasi kami mengabaikan overhead kecil ini.

Jadi, meskipun tidak ada arti pada lapisan aplikasi, duplikat ini bagi kami memberikan solusi yang berharga untuk menambahkan komentar ke sampel pengujian kami tanpa memutus kegunaan JSON.


Ini ide yang buruk. Dengan memasukkan kunci duplikat, bahkan jika Anda tidak perlu membaca data di dalamnya, Anda mengandalkan perilaku yang tidak ditentukan. Beberapa parser, seperti parser JSON-java Crockford, melemparkan pengecualian dan menolak untuk mengurai data.
Richard Smith

Sebenarnya bekerja dengan sempurna di lingkungan kita, jadi melayani kebutuhan saya, meskipun saya setuju dengan Anda bahwa itu semacam spesifikasi;)
aknoepfel

@ RichardSmith Saya akan mengatakan parser dan spesifikasi ES yang lebih baru telah mendefinisikan perilaku.
binki

2

Posting dan jawab karena ada banyak ide usang dan kebingungan tentang standar. Pada Desember 2017, ada dua standar yang bersaing:

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

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

json.org menyarankan ECMA-404 adalah yang standar, tapi situs ini tidak muncul untuk menjadi otoritas. Meskipun saya pikir adil untuk menganggap ECMA otoritas, yang penting di sini adalah, satu-satunya perbedaan antara standar (mengenai kunci unik) adalah bahwa RFC 8259 mengatakan kunci harus unik, dan ECMA-404 mengatakan mereka tidak diharuskan untuk menjadi ECMA-404. unik.

RFC-8259:

"Nama-nama dalam suatu objek HARUS unik."

Kata "harus" dalam semua huruf besar seperti itu, memiliki makna di dalam dunia RFC, yang secara spesifik didefinisikan dalam standar lain (BCP 14, RFC 2119 - https://tools.ietf.org/html/rfc2119 ) sebagai,

  1. HARUS Kata ini, atau kata sifat "DIREKOMENDASIKAN", berarti bahwa mungkin ada alasan yang valid dalam keadaan tertentu untuk mengabaikan item tertentu, tetapi implikasi penuh harus dipahami dan ditimbang dengan hati-hati sebelum memilih kursus yang berbeda.

ECMA-404:

"Sintaks JSON tidak memaksakan batasan pada string yang digunakan sebagai nama, tidak mengharuskan string nama menjadi unik, dan tidak memberikan signifikansi apa pun pada urutan pasangan nama / nilai."

Jadi, tidak masalah bagaimana Anda mengirisnya, JSON itu secara sintaksis valid .

Alasan yang diberikan untuk rekomendasi kunci unik di RFC 8259 adalah,

Objek yang namanya unik semuanya dapat dioperasikan dalam arti bahwa semua implementasi perangkat lunak yang menerima objek tersebut akan menyetujui pemetaan nama-nilai. Ketika nama-nama dalam suatu objek tidak unik, perilaku perangkat lunak yang menerima objek seperti itu tidak dapat diprediksi. Banyak implementasi melaporkan hanya pasangan nama / nilai terakhir. Implementasi lain melaporkan kesalahan atau gagal menguraikan objek, dan beberapa implementasi melaporkan semua pasangan nama / nilai, termasuk duplikat.

Dengan kata lain, dari sudut pandang RFC 8259, itu valid tetapi parser Anda mungkin muntah dan tidak ada janji yang, jika ada, nilai akan dipasangkan dengan kunci itu. Dari sudut pandang ECMA-404 (yang saya pribadi anggap sebagai otoritas), sah saja, titik. Bagi saya ini berarti bahwa setiap parser yang menolak untuk menguraikannya rusak. Setidaknya harus diuraikan sesuai dengan kedua standar ini. Tetapi bagaimana hal itu berubah menjadi objek pilihan Anda, dalam hal apa pun, kunci unik atau tidak, sepenuhnya bergantung pada lingkungan dan situasi, dan tidak ada yang standar dalam memulainya.


json.org sebenarnya mendahului standardisasi ECMA. Saya percaya itu sebenarnya dibuat oleh Crockford sendiri (itulah sebabnya ia memiliki plug tak tahu malu untuk bukunya). Pada saat itu, itu adalah wewenang JSON.
maks

1

Itu tidak didefinisikan dalam standar ECMA JSON . Dan secara umum, kurangnya definisi dalam standar berarti, "Jangan mengandalkan ini bekerja dengan cara yang sama di mana-mana."

Jika Anda seorang penjudi, "banyak" mesin JSON akan memungkinkan duplikasi dan cukup menggunakan nilai yang ditentukan terakhir. Ini:

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

Menjadi ini:

Object {a: 3, b: 2}

Tetapi jika Anda bukan penjudi, jangan mengandalkannya!


1

Standar mengatakan ini:

Bahasa pemrograman sangat bervariasi pada apakah mereka mendukung objek, dan jika demikian, karakteristik dan kendala apa yang ditawarkan objek. Model-model sistem objek bisa sangat berbeda dan terus berkembang. JSON sebagai gantinya memberikan notasi sederhana untuk mengekspresikan koleksi pasangan nama / nilai. Sebagian besar bahasa pemrograman akan memiliki beberapa fitur untuk mewakili koleksi seperti itu, yang dapat pergi dengan nama-nama seperti catatan, struct, dict, peta, hash, atau objek.

Bugnya setidaknya ada di node.js. Kode ini berhasil di node.js.

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

1
Ini bukan bug, dan bagian yang Anda kutip menjelaskan mengapa tidak: bahasa yang berbeda berperilaku berbeda, dan parser JSON akan melakukan apa yang paling alami untuk bahasa itu. Bagaimanapun, jawaban ini tidak menambahkan apa pun yang belum dikatakan pengguna454322 di atas.
Richard Smith

1

Menurut RFC-7159, standar saat ini untuk JSON yang diterbitkan oleh Internet Engineering Task Force (IETF), menyatakan "Nama-nama dalam suatu objek HARUS unik". Namun, menurut RFC-2119 yang mendefinisikan terminologi yang digunakan dalam dokumen-dokumen IETF, kata "harus" sebenarnya berarti "... mungkin ada alasan yang valid dalam keadaan tertentu untuk mengabaikan item tertentu, tetapi implikasi penuh harus dipahami dan hati-hati ditimbang sebelum memilih kursus yang berbeda. " Apa artinya ini pada dasarnya adalah bahwa walaupun memiliki kunci unik direkomendasikan, itu bukan keharusan. Kami dapat memiliki kunci duplikat di objek JSON, dan itu masih valid.

Dari aplikasi praktis, saya telah melihat nilai dari kunci terakhir dipertimbangkan ketika kunci duplikat ditemukan di JSON.


0

Dalam C # jika Anda deserialise ke Dictionary<string, string>itu dibutuhkan pasangan nilai kunci terakhir:

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

jika Anda mencoba untuk deserialise

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

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

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

Anda mendapatkan Newtonsoft.Json.JsonSerializationExceptionpengecualian.


2
saya kira itulah yang dilakukan sebagian besar (jika tidak semua), tetapi tidak menjawab pertanyaan saya jika valid pada spesifikasi JSON.
jepit

@viden: Ini bahkan bukan implementasi Microsoft ... ini adalah perpustakaan pihak ketiga.
BoltClock

@BoltClock Ah, sentuh.
svidgen
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.