快速且有效的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)類型。此外,還有To*方法可以嘗試轉換TJsonValue但如果轉換失敗,則返回提供的默認值。
您(可以)永遠不會創建TJsonValue的自己;創建TJsonValue的唯一方法是將值添加到JSON數組或字典中:
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ;此示例將TJsonValue (具有值42)添加到JSON數組中。要創建一個新的字典數組,您可以使用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單元。
您還可以使用類似XPath的JSONPATH實現來查詢JSON文檔。
沒有官方的JSONPATH規範,但使用最廣泛的版本似乎是Stefan Goessner開發的版本。
JSONPATH看起來像:
$.store.book[0].title或者
$['store']['book'][0]['title']兩種表示都相同:您可以使用dot( . )或括號( [] )表示法來表示字典的孩子。支架也可以與數值索引一起使用,以表示索引陣列的孩子。
JSONPATH僅在括號內使用單個引號(')。我們還允許雙引號(“),因為這些引號易於在Delphi字符串中使用。
簡而言之:
$表示根的開頭,其次是零或更多的子操作員( .或[] )。 $本身與整個文檔匹配。*或'*' )通配符,以匹配所有孩子。例如, $.store.book[*].author匹配商店中所有書籍的作者。. )外,可以使用雙點( .. )來搜索任何後代而不是直接的孩子。例如, $..author與所有作者匹配,而不論深度如何。這稱為遞歸下降。$.store.book[0,2,3]匹配第一本書,第三和第四本書。[Start:End:Step]與兒童的切片(範圍)匹配。這Start使用給定的Step尺寸(通常為1) End 。所有都是可選的,但必須給出至少一個值(和結腸):Start ,則暗示為0。負值表示從數組末端的偏移。End ,則切片將通過數組的末端提取。負值表示並從數組末端偏移。Step ,則暗示為1。List[2:]匹配第三個和所有元素。List[-2:]匹配最後兩個元素。List[:2]匹配前兩個元素。List[:-2]匹配最後兩個元素。List[2:-2]匹配所有元素,但前兩個和最後兩個元素。List[-4:-2]從末尾匹配第三元素和第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] | 第三本書 |
$..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 :使用UTF8String而不是無處不在的String 。所有字符串將被視為8位UTF-8字符串,而不是16位Unicode字符串。這樣可以減少內存消耗並加快解析。但是,這意味著您還必須將此JSON庫與UTF8Strings一起使用,否則Delphi將隱式轉換Unicode字符串和UTF8Strings,這可能會損害性能。JSON_STRING_INTERNING :啟用字典鍵的字符串Indioning。如果使用相同的鍵多次使用相同的鍵(當JSON從數據庫導出時很常見),這會減少內存的消耗,但要慢一些。 NESLIB.JSON單元根據JSON_UTF8定義,將JsonString類型聲明為String或UTF8String 。但是,這並不意味著您也必須使用JsonString 。如果您不在乎JSON_UTF8定義,則可以在此庫中使用常規字符串。
Neslib.JSON已根據簡化的BSD許可獲得許可。
有關詳細信息,請參見License.txt。