JSON 구문은 객체에서 중복 키를 허용합니까?


205

이것은 유효한 JSON입니까?

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

http://jsonlint.com/에서 예라고 말합니다.

http://www.json.org/ 는 금지 된 내용에 대해 아무 말도하지 않습니다.

그러나 분명히 이해가되지 않습니까? 대부분의 구현은 아마도 해시 테이블을 사용하므로 어쨌든 재정의됩니다.


1
당신이에 deserialise 경우 C 번호의 Json.NET은 첫 번째 키 쌍을 제거Dictionary<string, string>
샘 리치

누군가가 JSON 문자열에서 중복 값을 찾기위한 솔루션을 찾기 위해 여기에 도착하는 경우 무료 온라인 json 유효성 검사기
Pepijn Olivier를

jsonlint.com 은 그렇습니다. 마지막 키-값 쌍을 제외한 나머지를 모두 제거한 다음 유효성을 검사합니다.
Tim

7
그런 다음 표준이 깨졌습니다
Brad Thomas

1
키 이름 "-"을 주석 자로 사용했으며 값은 주석으로 단일 문자열 행입니다. 그래서 나는 파서가 그것에 대해 불평하지 않기를 바랍니다.
Lothar

답변:


126

에서 표준 (P II.) :

다른 표준은이 표준을 참조하여 JSON 텍스트 형식을 엄격하게 준수하면서 다양한 인코딩 세부 사항에 제한을 가할 것으로 예상됩니다. 이러한 표준은 특정 행동을 요구할 수 있습니다. JSON 자체는 동작을 지정하지 않습니다.

표준 (p. 2)에서 JSON 객체의 사양은 다음과 같습니다.

오브젝트 구조는 0 개 이상의 이름 / 값 쌍을 둘러싼 중괄호 토큰 쌍으로 표시됩니다. 이름은 문자열입니다. 단일 콜론 토큰은 이름과 값을 구분하여 각 이름 뒤에옵니다. 단일 쉼표 토큰은 다음 이름과 값을 구분합니다.

JSON 객체 다이어그램

중복 키가 유효하지 않거나 유효한 것은 언급하지 않았으므로 사양에 따라 안전하게 허용된다고 가정합니다.

JSON 라이브러리의 대부분의 구현은 할 수 없습니다 때문에 첫 번째 인용문의 표준으로하지 않습니다 충돌 중복 키에 동의합니다.

다음은 C ++ 표준 라이브러리와 관련된 두 가지 예입니다. 일부 JSON 객체를 직렬화 해제하면 std::map중복 키를 거부 하는 것이 좋습니다. 그러나 일부 JSON 객체를 직렬화 해제하면 std::multimap복제 키를 정상적으로 받아들이는 것이 좋습니다.


5
@PatrickGoley에 대한 언급을 좋아하지만 json.org에서 키 / 값 쌍 세트라고하며 고유하지 않음을 의미하는 유효하지 않은 것을 의미합니다.
클램프

8
@clamp json.org는 표준이 아니며, 내가 알 수 있듯이 Emca International이 운영하지 않습니다. json.org는 익명으로 제시된 것 같습니다. 사양 은 다음과 같습니다. ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf json.org의 내용은 관련이 없습니다.
Timothy Shields

5
@clamp std::multimap방금 추가 한 예를 고려하십시오 . 잠재적으로 중복 키가있는 JSON 객체로 직렬화 할 수 있습니다.
Timothy Shields

1
@clamp는 키 / 값 쌍의 집합으로 중복 이름을 배제하지 않습니다. {"a":1,"a":2}두 개의 고유 한 키 / 값 쌍 세트입니다. 실제로 {"a":1,"a":1}하나의 요소 만 갖는 일련의 키 / 값 쌍으로 생각할 수도 있습니다. 그것이 반복된다는 사실은 단지 구문상의 기발한 것으로 생각할 수 있습니다. 더 나은 정의는 "객체는 문자열 (이름)에서 값까지 부분 함수입니다."
Marcelo Cantos

2
@TimothyShields 그리고 당신이 연결 한 표준은 "JSON 구문은 이름으로 사용되는 문자열에 어떤 제한도 부과하지 않으며, 이름 문자열이 고유 할 필요는 없으며, 이름 / 값 쌍의 순서에 의미를 부여하지 않습니다"라고 말합니다.
Charles

135

짧은 대답 : 예, 권장하지 않습니다.
긴 대답 : 그것은 당신이 유효한 전화에 달려 있습니다 ...


ECMA-404 "JSON 데이터 교환 구문"은 중복 된 이름 (키)에 대해 아무 말도하지 않습니다.


그러나 RFC 8259 "JSON (JavaScript Object Notation) 데이터 교환 형식"은 다음과 같이 말합니다.

객체 내 이름은 고유해야합니다.

이러한 맥락에서 SHOULD 에서 지정하는 것으로 이해되어야한다 BCP 14 :

SHOULD 이 단어, 또는 형용사 "권장"는이 특정 항목을 무시하고 특정 상황에서 유효한 이유가있을 수 있지만, 전체 의미가 이해되어야 조심스럽게 다른 과정을 선택하기 전에 무게 것을 의미한다.


RFC 8259 는 고유 이름 (키)이 좋은 이유를 설명합니다.

이름이 모두 고유 한 객체는 해당 객체를받는 모든 소프트웨어 구현이 이름-값 매핑에 동의한다는 의미에서 상호 운용이 가능합니다. 개체 내에서 이름이 고유하지 않으면 해당 개체를받는 소프트웨어의 동작을 예측할 수 없습니다. 많은 구현에서 성 / 값 쌍만보고합니다. 다른 구현에서는 오류를보고하거나 개체를 구문 분석하지 못하고 일부 구현에서는 중복을 포함하여 모든 이름 / 값 쌍을보고합니다.



또한 Serguei가 ECMA-262 "ECMAScript® 언어 사양" 이라는 의견에서 지적한대로 다음과 같이 읽습니다.

객체 내에 중복 된 이름 문자열이있는 경우 동일한 키에 대한 사 전적으로 선행하는 값을 덮어 씁니다.

다시 말해, 마지막 가치는 이깁니다.


Douglas Crockford (JSON 제작자)가 Java 구현으로 이름이 중복 된 문자열을 구문 분석하려고 하면 예외가 발생합니다 .

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

1
JSON은 유효한 자바 스크립트이므로 중복 키가 리터럴에서 유효한 JS인지 확인하는 것이 중요합니다. : V8 그들을 받아들이는 것 같다 d8 -e 'x={"a":1,"a":2}; print(x.a);'이것은 2. 인쇄
벤 크로 웰

5
또한 ECMA-262 사양은 JSON.parse()명시 적으로 말합니다 In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.(즉, 최종 가치 승).
Serguei 2016 년

4
@BenCrowell : 마찬가지로 지금까지 내가 아는 한, JSON이 유효 자바 스크립트로 안되며, 그렇지 않은 경우는 참조가 timelessrepo.com/json-isnt-a-javascript-subset을 . 그렇게 말하면, 물론 자바 스크립트 (JSON 사양에서도 그렇게 말하고 있음)에서 많은 영감을 받았습니다.
Simon Touchtech

2
자바 스크립트 "엄격 모드"를 사용할 때 두 개의 동일한 키가있는 경우 크롬은 두 번째 키-값 쌍을 사용하고 첫 번째 키는 무시합니다. IE11에서 예외가 발생합니다.
Shahar

18

JSON 형식을 지정하는 2 개의 문서가 있습니다.

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

수락 된 답변은 첫 번째 문서에서 인용됩니다. 첫 번째 문서가 더 명확하다고 생각하지만 두 번째 문서에 더 자세한 내용이 포함되어 있습니다.

두 번째 문서는 다음과 같이 말합니다.

  1. 사물

    객체 구조는 0 개 이상의 이름 / 값 쌍 (또는 멤버)을 둘러싸는 중괄호 쌍으로 표시됩니다. 이름은 문자열입니다. 각 이름 뒤에 단일 콜론이 나타나 이름과 값을 구분합니다. 단일 쉼표는 다음 이름과 값을 구분합니다. 객체 내 이름은 고유해야합니다.

따라서 중복 이름을 사용하는 것은 금지되어 있지만 권장하지는 않습니다.


10

XML과 JSON을 모두 허용하는 API를 처리 할 때 비슷한 질문을 받았지만 JSON에서 중복 키가 될 것으로 예상되는 것을 처리하는 방법을 문서화하지 않았습니다.

다음은 샘플 JSON의 유효한 XML 표현입니다.

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

이것이 JSON으로 변환되면 다음과 같은 결과가 나타납니다.

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

중복 키라고하는 것을 처리하는 언어를 다른 언어로 자연스럽게 매핑하면 여기에서 잠재적 인 모범 사례 참조가 될 수 있습니다.

누군가를 돕는 희망!


5

JSON 사양은 다음과 같이 말합니다.

객체는 정렬되지 않은 이름 / 값 쌍 세트입니다.

여기서 중요한 부분은 "정렬되지 않은"것입니다. 특정 쌍을 참조하는 데 사용할 수있는 유일한 것은 키이기 때문에 키의 고유성을 의미합니다.

또한 대부분의 JSON 라이브러리는 JSON 객체를 역 직렬화하여 키가 고유하게 보장되는지도 / 사전을 해시합니다. 중복 키를 사용하여 JSON 객체를 직렬화 해제하는 경우 라이브러리에 따라 달라집니다. 대부분의 경우 오류가 발생하거나 각 중복 키의 마지막 값만 고려됩니다.

예를 들어 Python에서는을 json.loads('{"a": 1, "a": 2}')반환합니다 {"a": 2}.


23
순서가없는 것은 고유성을 의미합니까? 여기에 세트가
실용적인

8
정렬되지 않은 색상 모음 : 파랑, 녹색, 녹색, 파랑, 빨강, 파랑, 녹색-복제본이 있습니다.
Timothy Shields

5
"객체는 이름 / 값 쌍의 정렬되지 않은 세트입니다"라고 인용 한 텍스트 문구가 JSON 스펙에 나타나지 않습니다.
Timothy Shields

6
나는 당신이 json.org를 인용하고 있음을 알았습니다. 공식에 가깝지만 사양이 아닙니다. 페이지 상단에는 사양에 대한 링크가 있으며, 이는 json.org에서 그대로 반복됩니다. 사양을 검색하면 "정렬되지 않은"이라는 단어가 나타나지 않으며 "set"이라는 단어는 JSON 객체와 관련이없는 컨텍스트에서만 나타납니다.
Timothy Shields

5
이름이 아닌 "정렬되지 않은 이름 / 값 쌍 세트 "라고 표시되어 있습니다. 즉, { (a,b), (a,c) } 이다 독특한 세트. 따라서 기술적으로 json.org 정의 {"a":1,"a":2}는 유효하지만 유효 {"a":1,"a":2,"a":1}하지 않습니다. 또한 ECMA-404 (실제 표준)는 "set"이라는 단어를 사용하지 않습니다.An object structure is represented as a pair of curly bracket tokens surrounding zero or more name/value pairs.
Serguei

3

고유해야한다는 것이 반드시 고유해야한다는 의미는 아닙니다. 그러나 언급했듯이 일부 파서는 실패하고 다른 파서는 마지막으로 구문 분석 된 값을 사용합니다. 그러나 스펙이 중복을 허용하도록 약간 정리 된 경우 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>

나는 그 질문에 대한 추론을 볼 수 있지만 그것이 서있는 것처럼 ... 나는 그것을 믿지 않을 것입니다.


첫 번째 예제 배열에 쉼표가 없습니다. 또한 자체와 일치하지 않습니다. 사전을 정렬 된 컬렉션으로 사용하려는 경우 외부 배열도 객체 일뿐입니다. 즉 {"div":{"p":"hello","p":"universe"}, "div":{"h1":"Heading 1","p":"another paragraph"}}. 이제 많은 사람들과 프레임 워크가 JSON 객체를 정렬되지 않은 사전으로 취급하지만 JavaScript 및 MongoDB의 API는 사전 내의 키 순서에 의존하므로 제안하는 (순서 사전)은 들어 본 적이 없습니다. 당신은 특별한 파서가 필요합니다.
binki

2

목적을 요구하면 다른 답변이 있습니다.

JSON을 사용하여 객체를 직렬화 (JavaScriptObjectNotation)하면 각 사전 요소가 개별 객체 속성에 매핑되므로 동일한 속성에 대한 값을 정의하는 다른 항목은 의미가 없습니다.

그러나 API 테스트를 위해 JSON 샘플을 작성하는 매우 구체적인 사용 사례에서 같은 질문을 받았습니다. 유용성을 손상시키지 않고 JSON 파일에 주석을 추가하는 방법이 궁금했습니다. JSON 사양은 주석을 모르므로 매우 간단한 접근법을 생각해 냈습니다.

중복 키를 사용하여 JSON 샘플에 주석을 답니다 . 예:

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

우리가 사용하는 JSON 시리얼 라이저는 이러한 "REMARK"복제본에 문제가 없으며 애플리케이션 코드는이 작은 오버 헤드를 무시합니다.

따라서 애플리케이션 계층에는 아무런 의미가 없지만 이러한 중복은 JSON의 유용성을 손상시키지 않고 테스트 샘플에 주석을 추가하는 유용한 해결 방법을 제공합니다.


이것은 나쁜 생각입니다. 중복 키를 포함하면 데이터를 읽을 필요가 없더라도 정의되지 않은 동작에 의존하게됩니다. Crockford의 JSON-java 파서와 같은 일부 파서는 예외를 발생시키고 데이터 파싱을 거부합니다.
Richard Smith

실제로 우리 환경에서 완벽하게 작동하므로 사양에 맞지 않는다는 데 동의하더라도 내 요구를 충족시키는 것이 좋습니다.)
aknoepfel

@RichardSmith 파서와 최신 ES 사양이 동작을 정의했다고 말합니다.
binki

2

표준에 대한 오래된 아이디어와 혼란이 많기 때문에 게시하고 답변하십시오. 2017 년 12 월 현재 두 가지 경쟁 표준이 있습니다.

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)에 구체적으로 정의되어 있습니다.

  1. SHOULD이 단어 또는 형용사 "RECOMMENDED"는 특정 상황에서 특정 항목을 무시해야하는 유효한 이유가있을 수 있지만 다른 과정을 선택하기 전에 전체적인 의미를 이해하고 신중하게 고려해야합니다.

ECMA-404 :

"JSON 구문은 이름으로 사용되는 문자열에 제한을 두지 않으며 이름 문자열을 고유하게 요구하지 않으며 이름 / 값 쌍의 순서에 의미를 부여하지 않습니다."

따라서 슬라이스 방법에 관계없이 구문 상 유효한 JSON 입니다.

RFC 8259의 고유 한 키 권장 사항은 다음과 같습니다.

이름이 모두 고유 한 객체는 해당 객체를받는 모든 소프트웨어 구현이 이름-값 매핑에 동의한다는 의미에서 상호 운용이 가능합니다. 개체 내에서 이름이 고유하지 않으면 해당 개체를받는 소프트웨어의 동작을 예측할 수 없습니다. 많은 구현에서 성 / 값 쌍만보고합니다. 다른 구현에서는 오류를보고하거나 개체를 구문 분석하지 못하고 일부 구현에서는 중복을 포함하여 모든 이름 / 값 쌍을보고합니다.

다시 말해, RFC 8259의 관점에서 보면 유효하지만 파서는 바프 할 수 있으며 어떤 값이 해당 키와 쌍을 이룰 것인지에 대한 약속이 없습니다. ECMA-404 관점에서 (개인적으로 권한을 갖습니다) 유효 기간입니다. 나에게 이것은 파싱을 거부하는 파서가 손상되었음을 의미합니다. 적어도이 두 표준에 따라 구문 분석해야합니다. 그러나 그것이 선택하는 기본 객체로 바뀌는 방법은 어쨌든 환경과 상황에 완전히 의존하는 고유 키 여부이며, 그중 어느 것도 표준에 없습니다.


json.org는 실제로 ECMA 표준화보다 우선합니다. 나는 그것이 실제로 Crockford 자신에 의해 설정되었다고 생각합니다 (그래서 그의 책에 대한 뻔뻔한 플러그가 있습니다). 그 시점에서 그것은 JSON의 권한이었습니다.
최대

1

ECMA JSON 표준에 정의되어 있지 않습니다 . 그리고 일반적으로 표준의 정의가 부족하다는 것은 "이것이 모든 곳에서 같은 방식으로 작동한다고 생각하지 마십시오"를 의미합니다.

도박꾼 인 경우 "다수"JSON 엔진은 복제를 허용하고 마지막으로 지정된 값을 사용합니다. 이:

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

이것이된다 :

Object {a: 3, b: 2}

그러나 당신이 도박꾼이 아니라면, 그것을 의지하지 마십시오!


1

표준은 이것을 말합니다 :

프로그래밍 언어는 객체를 지원하는지 여부와 객체가 제공하는 특징 및 제약 조건에 따라 크게 다릅니다. 객체 시스템의 모델은 매우 다양하며 계속 발전하고 있습니다. JSON은 대신 이름 / 값 쌍 모음을 표현하기위한 간단한 표기법을 제공합니다. 대부분의 프로그래밍 언어에는 레코드, 구조체, 받아쓰기, 맵, 해시 또는 객체와 같은 이름으로 갈 수있는 이러한 컬렉션을 나타내는 기능이 있습니다.

버그는 최소한 node.js에 있습니다. 이 코드는 node.js에서 성공합니다.

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

1
버그가 아니며 인용 한 섹션에서 왜 그렇지 않은지를 설명합니다. 다른 언어는 다르게 동작하며 JSON 파서는 해당 언어에 가장 자연스러운 것을 수행합니다. 어쨌든,이 답변은 user454322가 아직 위에서 말하지 않은 것을 추가하지 않습니다.
Richard Smith

1

IETF (Internet Engineering Task Force)에서 게시 한 JSON의 현재 표준 인 RFC-7159에 따르면 "객체 내의 이름은 고유해야합니다"라고되어 있습니다. 그러나 IETF 문서에 사용 된 용어를 정의하는 RFC-2119에 따르면 "실제로"라는 단어는 실제로 "..."특정 상황에서 특정 항목을 무시해야하는 유효한 이유가있을 수 있지만 전체 의미를 이해하고 이해해야합니다. 다른 코스를 선택하기 전에 신중하게 무게를 측정했습니다. " 이것이 본질적으로 의미하는 것은 고유 키를 사용하는 것이 권장되지만 필수는 아닙니다. JSON 객체에 중복 키를 가질 수 있으며 여전히 유효합니다.

실제 응용 프로그램에서 JSON에서 중복 키가 발견되면 마지막 키의 값이 고려되는 것을 보았습니다.


0

C #에서 deserialize 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예외 가 발생합니다.


2
나는 그것이 전부는 아니지만 대부분의 구현이하는 것 같지만 JSON 사양으로 유효한 경우 내 질문에 대답하지 않습니다.
클램프

@ svidgen : 이것은 Microsoft의 구현조차도 아닙니다 ... 타사 라이브러리입니다.
BoltClock

@BoltClock 아, 감동.
svidgen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.