Быстрая и эффективная память объектная модель 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.
Вы также можете создавать новые документы JSON с нуля, используя методы CreateArray или CreateDictionary :
var
Doc: IJsonDocument;
begin
Doc := TJsonDocument.CreateArray;
Doc.Root.Add( 42 );
end ;Как вы можете видеть в этом примере, вы получаете доступ к объектной модели документа JSON через свойство root.
В основе объектной модели 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 вручную, если вы предпочитаете (например, чтобы избежать необходимости загружать объектную модель в память). Вы можете сделать это с интерфейсами IJsonReader и IJsonWriter в блоке Neslib.Json.IO .
Эти интерфейсы полностью независимы от любой реализации DOM и даже не требуют единицы Neslib.Json . Использование этих интерфейсов немного сложнее и требует больше работы. Смотрите подразделение Neslib.Json.IO для получения дополнительной информации.
Существует также реализация jsonpath, подобная XPath, которую вы можете использовать для запроса документов JSON.
Там нет официальной спецификации JSONPATH, но наиболее широко используемая версия, по -видимому, разработана Стефаном Гесснером.
GsonPath выглядит как:
$.store.book[0].titleили
$['store']['book'][0]['title'] Оба представления идентичны: вы можете использовать либо точку ( . ), Либо скобку ( [] ), чтобы обозначить детей словаря. Кроншеты также могут быть использованы с численными индексами для обозначения детей массива по индексу.
Jsonpath использует только отдельные цитаты (') в скобках. Мы также разрешаем двойные цитаты («), так как их легче использовать в струнах Delphi.
Суммируя:
$ , указывающего корень, за которым следуют ноль или более дочерних операторов ( . Или [] ). $ Сам по себе соответствует всем документам.* или '*' ), чтобы соответствовать всем детям. Например, $.store.book[*].author соответствует авторам всех книг в магазине.. ), Двойная точка ( .. ) может использоваться для поиска любых потомков, а не непосредственных детей. Например, $..author соответствует всем авторам, независимо от глубины. Это называется рекурсивным спуском.$.store.book[0,2,3] соответствует первой, третьей и четвертой книгам.[Start:End:Step] , чтобы соответствовать ломтике (диапазон) детей. Это соответствует всем детям из индекса, Start до (но не End ), используя заданный размер Step (обычно 1). Все это необязательно, но по крайней мере одно значение (и толстая кишка) должно быть дано:Start опущен, подразумевается, что это 0. Отрицательное значение указывает на смещение с конца массива.End опущен, срез избрасывает через конец массива. Отрицательное значение указывает и смещено с конца массива.Step пропущен, подразумевается, что будет 1.List[2:] соответствует третьим и всем следующим элементам.List[-2:] соответствует последним двум элементам.List[:2] соответствует первым двум элементам.List[:-2] соответствует всем, кроме двух последних элементов.List[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] | Третья книга |
$..book[-1:] | Последняя книга в порядке |
$..book[:2] | Первые две книги |
API JSONPATH короткий и простой. Он состоит из записи TJsonPath только с парой методов.
Для одноразового соответствия используйте метод статического Match :
var
Doc: IJsonDocument;
Matches: TArray<TJsonValue>;
begin
Doc := TJsonDocument.Load(...);
Matches := TJsonPath.Match(Doc, ' $.store.book[*].author ' );
end ;Если вы планируете использовать один и тот же путь в нескольких (sub) документах, то быстрее проанализировать путь один раз, а затем примените его несколько раз:
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 : чтобы включить ряд строк для ключей словарного. Это уменьшает потребление памяти в случае использования одного и того же ключа часто используется (что является обычным явлением, когда JSON экспортируется из базы данных), но немного медленнее. Блок Neslib.json объявляет тип JsonString как String или UTF8String , в зависимости от определения JSON_UTF8 . Тем не менее, это не означает, что вы также должны использовать JsonString . Если вы не заботитесь о определении JSON_UTF8 , то вы можете просто использовать обычные строки с этой библиотекой.
Neslib.json лицензирован по упрощенной лицензии BSD.
См. License.txt для деталей.