빠르고 메모리 효율적인 JSON 객체 모델로 JSON 호환 형식으로 효율적으로 구문 분석하고 쓰기를 지원합니다.
이 라이브러리는 Neslib 저장소에만 의존합니다. 이 저장소와 함께 하위 모듈로 포함됩니다.
이 라이브러리의 주요 항목은 IJsonDocument 인터페이스입니다. JSON 문서를 구문 분석,로드 및 저장하는 데 사용되며 JSON 객체 모델에 대한 액세스를 제공합니다. JSON 문자열을 다음과 같이 구문 분석 할 수 있습니다.
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.Parse( ' { "Answer" : 42 } ' );
end ;공식 JSON 사양과 달리이 라이브러리는 사전 키 주위의 따옴표가 필요 하지 않습니다 (키에 공백이나 다른 비 식별자 문자가 포함되지 않는 한). 따라서 다음도 유효합니다.
Doc := TJsonDocument.Parse( ' { Answer : 42 } ' ); Load 방법을 사용하여 파일이나 스트림에서로드 할 수도 있습니다.
출력 측면에서는 Save 사용하여 파일 또는 스트림에 저장 또는 JSON 문자열로 출력하기 위해 ToJson 합니다.
CreateArray 또는 CreateDictionary 메소드를 사용하여 새로운 JSON 문서를 처음부터 만들 수도 있습니다.
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ;이 예에서 볼 수 있듯이 루트 속성을 통해 JSON 문서 객체 모델에 액세스하십시오.
JSON 객체 모델의 핵심에는 TJsonValue 유형이 있습니다. 이것은 모든 유형의 JSON 값을 보유 할 수있는 레코드입니다.
TJsonValue 다른 (DELPHI) 유형으로 변환하기 위해 다양한 암시 적 변환 연산자를 제공합니다. 또한 TJsonValue 를 변환하려고 시도하는 다양한 To* 이 있지만 변환이 실패하면 제공된 기본값을 반환합니다.
당신은 TJsonValue 자신을 결코 만들 수 없습니다. TJsonValue 생성하는 유일한 방법은 JSON 배열 또는 사전에 값을 추가하는 것입니다.
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ; 이 예제는 JSON 어레이에 TJsonValue (값 42)를 추가합니다. 새로운 사전 배열을 만들려면 대신 AddArray 또는 AddDictionary 메소드를 사용합니다.
var
Doc: IJsonDocument;
Dict: TJsonValue;
begin
Doc := TJsonDocument.CreateArray;
Dict := Doc.Root.AddDictionary;
Dict.AddOrSetValue( ' answer ' , 42 );
end ;이것은 새로운 사전을 생성하고 루트 배열에 추가합니다. 그런 다음 값 42는 '답변'이라는 이름 으로이 사전에 추가됩니다.
값의 유형을 확인하려면 TJsonValue.ValueType 속성 또는 TJsonValue.Is* 메소드 중 하나를 사용하십시오.
배열 (또는 사전)이 아닌 값에서 Add (또는 AddOrSetValue )와 같은 메소드를 사용하려고 할 때 예외가 발생합니다.
그러나 배열 ( Items 속성 사용) 또는 사전의 값 ( Values 속성 사용)의 값에 액세스하면 배열 인덱스가 한계를 벗어난 경우에도 예외가 발생하지 않습니다. 이를 통해 각 중간 단계의 유효성을 확인하지 않고도 여러 배열/사전 액세스를 함께 체인 할 수 있습니다. 예를 들어:
I := Doc.Root.Items[ 3 ].Values[ ' foo ' ].Values[ ' bar ' ].Items[ 4 ].ToInteger( 0 );이것은 항상 성공하지만 중간 값을 사용할 수없는 경우 0을 반환합니다.
IJsonDocument 인터페이스를 사용하면 JSON이 문서 개체 모델에 쉽게 읽고 쓸 수 있습니다.
그러나 원하는 경우 (예 : 객체 모델을 메모리에로드하지 않아도) JSON을 수동으로 읽거나 쓸 수도 있습니다. Neslib.Json.IO 단위의 IJsonReader 및 IJsonWriter 인터페이스로이를 수행 할 수 있습니다.
이 인터페이스는 모든 DOM 구현과 완전히 독립적이며 Neslib.Json 장치조차 필요하지 않습니다. 이러한 인터페이스를 사용하는 것은 조금 더 복잡하며 더 많은 작업이 필요합니다. 자세한 내용은 Neslib.Json.IO 단위를 참조하십시오.
JSON 문서 쿼리에 사용할 수있는 XPath와 같은 JSONPATH 구현도 있습니다.
공식 JSONPATH 사양은 없지만 가장 널리 사용되는 버전은 Stefan Goessner가 개발 한 것 같습니다.
JSONPATH는 다음과 같습니다.
$.store.book[0].title또는
$['store']['book'][0]['title'] 두 표현 모두 동일합니다. DOT ( . ) 또는 브래킷 ( [] ) 표기법을 사용하여 사전의 어린이를 표시 할 수 있습니다. 괄호는 또한 수치 지수와 함께 사용하여 배열의 어린이를 색인별로 표시 할 수 있습니다.
JSONPATH는 괄호 안에 단일 따옴표 ( ') 만 사용합니다. 또한 델파이 문자열에서 사용하기가 더 쉽기 때문에 이중 인용문 ( ")도 허용합니다.
요컨대 :
$ 로 시작하고 0 이상의 어린이 운영자 ( . 또는 [] )가 이어집니다. A $ 자체는 전체 문서와 일치합니다.* 또는 '*' ) 와일드 카드 일 수 있습니다. 예를 들어, $.store.book[*].author 상점의 모든 책의 저자와 일치합니다.. ) 외에도 이중 점 ( .. )을 사용하여 직계 자녀 대신 자손을 검색 할 수 있습니다. 예를 들어, $..author 깊이에 관계없이 모든 저자와 일치합니다. 이것을 재귀 하강이라고합니다.$.store.book[0,2,3] 첫 번째, 세 번째 및 네 번째 책과 일치합니다.[Start:End:Step] 사용하여 어린이의 슬라이스 (범위)와 일치 할 수 있습니다. 이것은 주어진 Step 크기 (보통 1)를 사용하여 Index Start Up (하지만 포함하지 않음) End 의 모든 어린이와 일치합니다. 모두 선택 사항이지만 하나 이상의 값 (및 결장)이 제공되어야합니다.Start 생략되면 0이라는 것을 암시합니다. 음수 값은 배열 끝에서 오프셋을 나타냅니다.End 생략되면 슬라이스는 배열 끝을 통해 추출됩니다. 음수 값은 배열 끝에서 오프셋을 나타냅니다.Step 생략되면 1이라는 것을 암시합니다.List[2:] 는 세 번째 및 모든 요소와 일치합니다.List[-2:] 는 마지막 두 요소와 일치합니다.List[:2] 는 처음 두 요소와 일치합니다.List[:-2] 마지막 두 요소를 제외한 모든 일치합니다.List[2:-2] 는 모든 요소와 일치하지만 처음 두 개와 마지막 두 요소와 일치합니다.List[-4:-2] 끝에서 3 번째 및 네 번째 요소와 일치합니다.List[::2] 는 모든 요소와 짝수 인덱스와 일치합니다.JSONPATH에는 또한 사용자 지정 스크립트 표현식을 허용하는 @ 연산자가 있습니다. 우리는이 연산자를 지원하지 않습니다.
예제 문서 :
{ "store" : {
"book" : [
{ "category" : " reference " ,
"author" : " Nigel Rees " ,
"title" : " Sayings of the Century " ,
"price" : 8.95
},
{ "category" : " fiction " ,
"author" : " J. R. R. Tolkien " ,
"title" : " The Lord of the Rings " ,
"isbn" : " 0-395-19395-8 " ,
"price" : 22.99
}
],
"bicycle" : {
"color" : " red " ,
"price" : 19.95
}
}
}예제 경로 :
| 표현 | 결과 |
|---|---|
$ | 루트 문서와 일치합니다 (단일 값) |
$..* | 문서의 모든 멤버와 일치합니다 (많은 값) |
$.store.book[*].author | 가게의 모든 책의 저자 |
$..author | 모든 저자 |
$.store.* | 매장 내 모든 것 (2 권의 책과 자전거) |
$.store..price | 상점의 모든 가격 |
$..book[2] | 세 번째 책 |
$..book[-1:] | 마지막 책 순서 |
$..book[:2] | 처음 두 권의 책 |
JSONPATH API는 짧고 간단합니다. 그것은 몇 가지 방법 만있는 TJsonPath 레코드로 구성됩니다.
일회성 일치의 경우 정적 Match 방법을 사용하십시오.
var
Doc: IJsonDocument;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Matches := TJsonPath.Match(Doc, ' $.store.book[*].author ' );
end ;여러 (서브) 문서에서 동일한 경로를 사용하려는 경우 경로를 한 번 구문 분석 한 다음 여러 번 적용하는 것이 더 빠릅니다.
var
Doc1, Doc2: IJsonDocument;
Path: TJsonPath;
Matches1, Matches2: TArray<TJsonValue>;
begin
Doc1 := TJsonDocument.Load(...);
Doc2 := TJsonDocument.Load(...);
Path := TJsonPath.Create( ' $.store.book[*].author ' );
Matches1 := Path.Match(Doc1);
Matches2 := Path.Match(Doc2);
end ;서브 트리의 경로를 실행할 수도 있습니다.
var
Doc: IJsonDocument;
Store: TJsonValue;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Store := Doc.Root.Values[ ' store ' ];
Matches := TJsonPath.Match(Store, ' $.book[*].author ' );
end ; 단일 (또는 첫 번째) 경기에만 관심이 있다면 대신 MatchSingle 사용할 수 있습니다.
var
Doc: IJsonDocument;
Match: TJsonValue;
begin
Doc := TJsonDocument.Load(...);
if (TJsonPath.MatchSingle(Store, ' $.book[*] ' , Match)) then
...
end ; 이 JSON 라이브러리의 모든 메모리 관리는 자동입니다. IJsonDocument 인터페이스는 모든 TJsonValue 를 소유하고 문서가 파괴 될 때이를 파괴합니다 (범위를 벗어납니다).
알아야 할 유일한 것은 문서가 파괴 된 후 더 이상 tjsonValue 레코드를 사용해서는 안된다는 것입니다. 그렇게하면 정의되지 않은 행동과 충돌이 발생할 수 있습니다.
이러한 조건부 정의를 사용하여 일부 동작을 사용자 정의 할 수 있습니다.
JSON_UTF8 : 모든 곳에서 String 대신 UTF8String 사용합니다. 모든 문자열은 16 비트 유니 코드 스트링 대신 8 비트 UTF-8 문자열로 취급됩니다. 이것은 메모리 소비를 줄이고 약간의 구문 분석 속도를 높입니다. 그러나 이것은이 JSON 라이브러리를 UTF8Strings와 함께 사용해야한다는 것을 의미합니다. 그렇지 않으면 Delphi는 유니 코드 문자열과 UTF8strings를 암시 적으로 변환하여 성능을 손상시킬 수 있습니다.JSON_STRING_INTERNING : 사전 키를위한 문자열 인턴을 활성화합니다. 이는 동일한 키가 여러 번 사용되는 경우 메모리 소비를 줄이지 만 (JSON이 데이터베이스에서 내보낼 때 일반적이지만) 약간 느립니다. neslib.json 단위는 JSON_UTF8 정의에 따라 JsonString 유형을 String 또는 UTF8String 으로 선언합니다. 그러나 이것이 JsonString 사용해야 한다는 의미는 아닙니다. JSON_UTF8 DEFINE에 신경 쓰지 않으면이 라이브러리와 함께 일반 문자열을 사용할 수 있습니다.
Neslib.json은 단순화 된 BSD 라이센스에 따라 라이센스가 부여됩니다.
자세한 내용은 License.txt를 참조하십시오.