среда, 10 апреля 2013 г.

JSONные войны в Lazarus

Нужно было освоить формат JSON. Конкретнее - его распарсивание. После некоторых поисков была найдена нужная библиотека и примеры.

JSON читаю из файла в строку (это для тестирования, потом он будет изначально в строке) и передаю в функцию.
{
"system":{version:"1.0"},
"chains":[1,2],
"devices":[
{"id":1,"type":"07"}
]
}

Распарсенный JSON мне нужно хранить в переменной и периодически обращаться к нему для получения данных.
Для работы мне понадобилось два модуля : fpjson, jsonparser.
Из них три класса: TJSONData , TJSONParser и TJSONObject.
TJSONObject - это тот объект который подходит для хранения и манипулирования JSON структурой. Хранить буду в нем.
TJSONParser - парсит строку и выдает результат в виде объекта TJSONData. TJSONData - довольно бестолковый класс, у него мало методов для работы со структурой. Когда пытался добавить данные в TJSONObject выяснилось что они добавляются только как дочерние объекты, то есть например на ключ test:

{"test":{
"system":{version:"1.0"},
"chains":[1,2],
"devices":[
{"id":1,"type":"07"}
]
}}


Это обстоятельство не очень понравилось. Написал небольшой класс с методом загрузки структуры из строки один в один.


unit json;

interface

uses
  SysUtils, fpjson,jsonparser;

type
  TJSON = class(TJSONObject)
  public
    function ifExistKey(aKey: string): Boolean;
    function Parse(aString: string): Boolean;
  end;

implementation

function TJSON.ifExistKey(aKey: string): Boolean;
begin
  result:=(Find(aKey)<>nil);
end;

function TJSON.Parse(aString: string): Boolean;
var
  D : TJSONData;
  P : TJSONParser;
  i:Integer;
begin
  result:=false;
  P:=TJSONParser.Create(aString);
  D:=P.Parse;
  Clear;
  try
    for i:=0 to D.Count-1 do begin
      Add(TJSONObject(D).Names[i],TJSONObject(D).Items[i]);
    end;
  except
    FreeAndNil(P);
    exit;
  end;

  FreeAndNil(P);
  result:=true;
end;

end.


метод Parse(s:String) возвращает false в случае ошибки
метод ifExistKey(key:String) проверяет есть ли узел с указанным ключом на главном уровне.

Использую примерно так:


var
  JS:TJSON;
  fd:THandle;
  filename:string;
  Buffer:String;
begin

  filename:=IncludeTrailingBackslash(ExtractFileDir(ParamStrUTF8(0)))+'test.json';
  fd:=FileOpenUTF8(filename, fmOpenRead);
  SetLength(Buffer,FileSize(filename));
  FileRead(fd,Buffer[1],Length(Buffer));
  FileClose(fd);

  JS:=TJSON.Create;
  JS.Parse(Buffer);
  ShowMessage(JS.FormatJSON); // чтобы посмотреть что там у нас
end;

Краткое описание класса TJSONObject.

FormatJSON:String // выводит в строку всю структуру JSON
Find(Const AName : String) : TJSONData; // находит указанный узел по имени ключа
Get(Const AName : String) ???? // возвращает данные по ключу. функций много, по количеству возвращаемых типов. Смотрите справку.
Clear; // очистка
Add // опять же много функций, для каждого типа своя.
Delete(ключ или индекс) // удаляет узел
свойство Names[Index : Integer] // узнать название узла
свойство Items[Index: Integer]: TJSONData // получить данные узла
свойство Elements[AName: string] : TJSONData // получить данные узла по имени ключа
свойство Objects[AName : String] : TJSONObject // получить данные узла по имени ключа в виде объекта TJSONObject
Ну и конечно же функция Count - количество узлов на главном уровне.

Так вот сходу не найду ссылку на справку, можете посмотреть в самом модуле fpjson, там всё с комментариями.

P.S. Обнаружил ошибку в этом коде. Утечки памяти.
Вот тут исправляю:  JSON: Работа над ошибками

Комментариев нет:

Отправить комментарий