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を使用してファイルまたはストリームに保存するか、 ToJson JSON文字列に出力します。
また、 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']どちらの表現も同一です:辞書の子供を示すために、ドット( . )またはブラケット( [] )表記のいずれかを使用できます。ブラケットは、インデックスごとに配列の子供を示すために数値インデックスで使用することもできます。
JSonPathは、括弧内で単一の引用( ')のみを使用します。また、Delphi文字列で使いやすいため、二重引用符( ")も許可します。
要するに:
$から始まり、その後にゼロ以上の子オペレーター( .または[] )が続きます。 A $自体がドキュメント全体と一致します。*または'*' )のワイルドカードです。たとえば、 $.store.book[*].author店内のすべての本の著者と一致します。. )に加えて、二重ドット( .. )を使用して、すぐ近くの子供の代わりに子孫を検索できます。たとえば、 $..author 、深さに関係なく、すべての著者と一致します。これは再帰降下と呼ばれます。$.store.book[0,2,3]最初、3冊目、4冊目の本と一致します。[Start:End:Step]を使用して、子供のスライス(範囲)を一致させることができます。これは、特定のStepサイズ(通常は1)を使用して、インデックスのStartからEndまでのすべての子供と一致します。すべてはオプションですが、少なくとも1つの値(およびコロン)を指定する必要があります。Startが省略されている場合、それは0であると暗示されます。負の値は、配列の端からのオフセットを示します。Endを省略した場合、スライスは配列の端から抽出します。負の値は、アレイの端からのオフセットを示し、オフセットします。Stepが省略されている場合、1であると暗示されています。List[2:] 、3番目とすべての次の要素と一致します。List[-2:]最後の2つの要素と一致します。List[:2]最初の2つの要素と一致します。List[:-2]最後の2つの要素を除くすべてと一致します。List[2:-2]最初の2つと最後の2つを除くすべての要素と一致します。List[-4:-2]最後の3番目と4番目の要素と一致します。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] | 3番目の本 |
$..book[-1:] | 最後の本 |
$..book[:2] | 最初の2冊の本 |
JSonPath APIは短くてシンプルです。これは、いくつかの方法しかないTJsonPathレコードで構成されています。
1回限りのマッチングには、静的Matchメソッドを使用します。
var
Doc: IJsonDocument;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Matches := TJsonPath.Match(Doc, ' $.store.book[*].author ' );
end ;複数の(サブ)ドキュメントで同じパスを使用する場合は、パスを1回解析してから複数回適用する方が速いです。
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 ; 1つの(または最初の試合)のみに興味がある場合は、代わりに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文字列として扱われます。これにより、メモリの消費が削減され、少し速度が上がります。ただし、これは、UTF8Stringsを備えたこのJSONライブラリも使用する必要があることを意味します。そうしないと、Delphiはパフォーマンスを損なう可能性のあるUnicode文字列とUTF8Strings間で暗黙的に変換します。JSON_STRING_INTERNING :辞書キーの文字列インターンを有効にする。これにより、同じキーが多くの場合使用される場合にメモリ消費が削減されます(これは、JSONがデータベースからエクスポートされる場合に一般的です)が、少し遅いです。 neslib.jsonユニットは、 JSON_UTF8定義に応じて、 JsonStringタイプをStringまたはUTF8Stringとして宣言します。ただし、これは、 JsonStringを使用する必要があるという意味ではありません。 JSON_UTF8定義を気にしない場合は、このライブラリで通常の文字列を使用できます。
neslib.jsonは、簡素化されたBSDライセンスの下でライセンスされています。
詳細については、license.txtを参照してください。