уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Сегодняшняя тема, думаю, будет интересна в первую очередь тем, кто связан с программированием сетевых приложений. Про работу с JSON в Delphi я уже несколько раз рассказывал в блоге и приводил примеры того как можно разбирать различные JSON-объекты. Но во всех примерах я рассматривал работу лишь с одной из библиотек для работы с json в Delphi — SuperObject.

Но не стоит забывать и про то, что в Delphi существуют свои родные механизмы работы с JSON, которые содержатся в трех модулях: DBXJSON.pas, DBXJSONCommon.pas и DBXJSONReflect.pas. В этих трех модулях можно найти достаточно много полезных и интересных классов и методов. Если Вы никогда не слышали об этих модулях, то эта статья как раз для Вас.

В последних версиях Delphi все функции работы с JSON вынесены в модули System.JSON, System.JSON.BSON, System.JSON.Builders, System.JSON.Readers, System.JSON.Types, System.JSON.Utils, System.JSON.Writers, System.JSONConsts.

 

Введение

О возможностях работы с JSON в Delphi 10.3 Rio читайте эту статью

Впервые о том, что Delphi теперь «умеет» работать с JSON я узнал после выхода Delphi 2010. Тогда в исходниках были замечены  два модуля: DBXJSON.pas и DBXJSONReflect.pas. Ну, а раз именно эти два модуля появились в Delphi первыми, то с них мы и начнем разговор, но прежде, пара слов о формате JSON.

JSON — это текстовый формат обмена данными. В основе этого формате лежит всего пять понятий:

  1. Объект — неупорядоченный набор пар «ключ/значение». Объект всегда начинается с «{» и заканчивается «}».
  2. Массив — упорядоченный коллекция значений. Массив начинается с «[» и заканчивается «]». Элементы массива разделяются запятыми.
  3. Значение — строка в двойных кавычках. Значение может быть: строкой, числом, true, false, null, объектом, массивом.
  4. Строка — набор Unicode-символов.
  5. Число — любое число в десятичной системе счисления.
В соответствии с этими понятиями и организован механизм работы с JSON в Delphi. Открыв модуль DBXJSON.pas Вы можете обнаружить там следующие классы:
  1. TJSONObject — объект
  2. TJSONArray —  массив 
  3. TJSONValue — значение
  4. TJSONString — строка
  5. TJSONNumber — число
Для работы с различными значениями JSON также предусмотрены соответствующие классы:
  • TJSONString — строка
  • TJSONNumber — число
  • TJSONTrue — true
  • TJSONFalse — false
  • TJSONNull — null
Для получения пары «ключ/значение» используется класс TJSONPair. От нас же требуется грамотно воспользоваться представленными выше классами и либо прочитать объект JSON, либо наоборот — записать. Этим мы сейчас и займемся.

Использование DBXJSON.pas

Чтение данных

В качестве примера работы с различными классами из модуля DBXJSON.pas разберем такой объект:

{"kind":"tasks#tasks",
 "etag":"ptcy4Awv48HyN47i0A",
 "items":[
          {"kind":"tasks#task",
           "id":"MTc4Njk1MjA4MTEyODY5OTA4",
           "title":"Задача №1",
           "updated":"2011-10-15T10:07:16.000Z",
           "selfLink":"https://www.googleapis.com/tasks/v1/lists/MTcw/tasks/MyMTEyODY5OTA4",
           "position":"00000000000000131071",
           "status":"needsAction",
           "due":"2011-10-14T00:00:00.000Z"},
 
           {"kind":"tasks#task",
            "id":"MTc4Njk1MjA4NTYyMTMzMDA",
            "title":"Задача №2",
            "updated":"2011-10-15T09:41:50.000Z",
            "selfLink":"https://www.googleapis.com/tasks/v1/lists/MTcw/tasks/MTc4Njk1MjA4MTMzMDA",
            "position":"00000000000000196607",
            "status":"completed",
            "completed":"2011-10-15T09:41:50.000Z"}
         ]
}

Постоянные читатели блога могут сразу догадаться почему именно такой объект я выбрал в качестве примера. Это JSON-объект из Google Tasks API, содержащий список задач. Вначале посмотрим из чего состоит объект.

Вначале объекта идут две пары, содержащие служебную информацию по ответу — kind, значение которого говорит нам, что мы запросили список задач и Etag — идентификатор ответа. Далее следует массив items в котором каждый элемент — это объект, содержащий сведения по отдельной задаче.

При этом следует обратить внимание на то, что каждый JSON-объект задачи может состоять из различных пар.В примере выше Вы можете видеть, что «Задача №1» содержит сведения по сроку выполнения задачи («due«), в то время как «Задача №2» не имеет срока выполнения, но зато отмечена как выполненная («completed«).

Приложение для парсинга JSON

Чтобы наиболее полно охватить работу с DBXJSON.pas, используя предложенный выше JSON-объект, вначале напишем небольшое приложение, которое будет парсить данные из файла, содержащего JSON-объект и «рассказывать» нам о том, что содержится в JSON-объекте и «подсказывать» какой класс будет использоваться для парсинга значений из той или иной пары. Для этого сохраним объект, предложенный выше в текстовый файл с названием testObject.txt,  создадим новый проект Delphi-приложения  и на главной форме разместим следующие компоненты:

Работа программы будет происходить следующим образом:

  • при открытии очередного файла пробуем разобрать, содержащиеся в файле данные
  • если удалось провести парсинг данных из файла, то записываем в ComboBox имена пар, иначе — сообщаем пользователю о том, что файл не содержит JSON-данных
  • при выборе значения в ComboBox’e выводим значение пары в виде строки в Memo и определяем класс, который необходимо использовать для парсинга значения пары.

Вначале напишем обработчик OnClick кнопки:

type
  Tfmain = class(TForm)
    [...]
  private
    FJSONObject: TJSONObject;
  public
  end;
 
procedure Tfmain.Button1Click(Sender: TObject);
var S: TStringList;
begin
  if OpenDialog1.Execute then
    begin
      lbPathToFile.Caption:=OpenDialog1.FileName;
      S:=TStringList.Create;
      try
        //читаем файл
        S.LoadFromFile(OpenDialog1.FileName);
        //пробуем распарсить
        FJSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
        if Assigned(FJSONObject) then //парсинг прошел успешно - считываем названия пар
          EnumPairs
        else //парсинг провалился - выводим сообщение
          raise Exception.Create('Файл не содержит JSON-данные');
      finally
        S.Free;
      end;
    end;
end;

Здесь мы воспользовались одним из четырех перегруженных классовых методом у TJSONObject для получения JSON-объекта и передали в метод строку. Также мы могли бы воспользоваться следующими методами для парсинга:

class function ParseJSONValue(const Data: TBytes; const Offset: Integer; IsUTF8: Boolean = True): TJSONValue; overload; static;
class function ParseJSONValue(const Data: TBytes; const Offset: Integer; const Count: Integer; IsUTF8: Boolean = True): TJSONValue; overload; static;
class function ParseJSONValue(const Data: String): TJSONValue; overload; static;
class function ParseJSONValue(const Data: UTF8String): TJSONValue; overload; static;

Как видите в качестве параметров метода можно задать массив байт (TBytes), Unicode-строку или UTF8-строку. Я решил воспользоваться самым простым вариантом — использовать Unicode-строку и читать файл с самого начала без сдвигов (параметр Offset в методах).

Следующий наш шаг — чтение названий пар. Для этого в программе реализован метод EnumPairs, который выглядит следующим образом:

procedure Tfmain.EnumPairs;
var i:integer;
begin
cbPairs.Clear;
  for I := 0 to FJSONObject.Size-1 do
    cbPairs.Items.Add(FJSONObject.Get(i).JsonString.Value);
end;

Рассмотрим, что здесь делается.
Во-первых, мы воспользовались свойством Size объекта FJSONObject, которое возвращает нам количество пар, содержащихся в объекте.
Во-вторых, мы воспользовались методом Get, который возвращает нам отдельную пару (объект типа TJSONPair). В TJSONObject содержится два перегруженных метода Get первый из которых возвращает пару по её номеру, второй — по имени:

function Get(const I: Integer): TJSONPair; overload;
function Get(const PairName: UnicodeString): TJSONPair; overload;

Так как мы не можем знать какой объект содержится в файле и какие пары есть в объекте, то воспользовались первым вариантом Get — с использованием индексов.
В-третьих, после того, как метод Get вернул нам пару, мы, используя свойство JSONString типа TJSONString прочитали имя пары (свойство Value) и добавили его в ComboBox.

Следующий шаг — вывод строкового значения пары в Memo и определение класса для парсинга этого значения. Для этого напишем обработчик OnChange у ComboBox:

procedure Tfmain.cbPairsChange(Sender: TObject);
begin
  mmPairValue.Clear;
  mmPairValue.Text:=FJSONObject.Get(cbPairs.ItemIndex).JsonValue.ToString;
  lbClass.Caption:=FJSONObject.Get(cbPairs.ItemIndex).JsonValue.ClassName
end;

Здесь мы воспользовались вторым свойством пары TJSONPairJSONValue, которое в отличие от JSONString имеет тип TJSONValue. При этом следует обратить внимание на следующий момент:
Имя пары — это всегда какая-либо строка, в то время как значение может быть и строкой и массивом и числом и т.д. Поэтому для вывода строкового значения пары я воспользовался именно методом ToString, а не использовал свойство TJSONValue.Value, которое вернуло бы мне вместо значения пустую строку, в случае, если бы в значении содержался бы, например, массив.

Ну, а далее, имея значение пары мы просто вывели в Label имя класса для JSONValue.

Вот и вся программа. Теперь запустим программу и проверим работу на нашем объекте, который, как Вы помните, мы сохранили в файл TestObject.txt. Скрин работающей программы представлен ниже:


Чтение свойств класса из JSON-объекта

Теперь, имя под рукой наше приложение, мы можем легко определить какой класс надо использовать для парсинга значений той или иной пары, а значит можем вернуться к нашему объекту со списком заданий и распарсить его вдоль и поперек. Для примера создадим класс, содержащий все возможные свойства для задания из Google Tasks (какие это свойства можно глянуть в документации к API). У меня класс получился следующий:

TTaskResource = class()
  private
    FId: string;
    FTitle: string;
    FUpdated: TDateTime;
    FSelfLink: string;
    FParent: string;
    FPosition: string;
    FNotes: string;
    FStatus: string;
    FDue: TDateTime;
    FCompleted: TDateTime;
    FDeleted: string;
    FHidden: string;
    procedure SetCompleted(const Value: TDateTime);
    procedure SetDue(const Value: TDateTime);
    procedure SetId(const Value: string);
    procedure SetNotes(const Value: string);
    procedure SetStatus(const Value: string);
    procedure SetTitle(const Value: string);
    procedure ParseJSON(Value: TJSONValue);
  public
    constructor Create;
    property Id: string read FId;
    property Title: string read FTitle write SetTitle;
    property Updated: TDateTime read FUpdated;
    property SelfLink: string read FSelfLink;
    property Parent: string read FParent;
    property Position: string read FPosition;
    property Notes: string read FNotes write SetNotes;
    property Status: string read FStatus write SetStatus;
    property Due: TDateTime read FDue write SetDue;
    property Completed: TDateTime read FCompleted write SetCompleted;
    property Deleted: string read FDeleted;
    property Hidden: string read FHidden;
  end;

Как уже было сказано выше, объект, содержащий свойства задания может состоять из различного количества пар в зависимости от того, какое задание передается (завершенное или нет, со сроком выполнения или нет и т.д.). В связи с этим метод ParseJSON должен не просто выбирать пары по их именам, а по примеру нашей программы считывать пары по их индексам и уже после этого определять что это за пара и заполнять соответствующее поле. Метод ParseJSON можно представить так:

procedure TTaskResource.ParseJSON(Value: TJSONValue);
var
  JObject: TJSONObject;
  JPair: TJSONPair;
  i:integer;
  MemberName: string;
begin
  if not Assigned(Value) then  Exit;
  JObject := (Value as TJSONObject);//привели значение пары к классу TJSONObject
  try
    {проходим по каждой паре}
    for I := 0 to JObject.Size-1 do
      begin
        JPair:=JObject.Get(i);//получили пару по её индексу
        MemberName:=JPair.JsonString.Value;//определили имя
        {ищем в какое свойство записывать значение}
        if MemberName=cKindTag then
          FKind:=JPair.JsonValue.Value
        else
          [...]
          else
            if MemberName=cDeletedTag then
               FDeleted:=JPair.JsonValue.Value
            else
              if MemberName=cHiddenTag then
                FHidden:=JPair.JsonValue.Value;
      end;
  except
    raise Exception.Create('Ошибка разбора JSON');
  end;
end;

Здесь мы уже без лишних проверок используем свойство Value у TJSONValue, т.к. мы знаем, что за класс содержится в значении каждой пары (это TJSONString). Двигаемся далее. Процедура выше — это только парсинг пар в известном объекте. Но наш главный объект для парсинга содержит целый массив таких классов (см. выше листинг объекта). Поэтому следует предусмотреть работу с JSON-массивом.

Для работы с JSON-массивами в модуле DBXJSON.pas предусмотрено два класса:

  • TJSONArray — класс массива
  • TJSONArrayEnumerator — перечислитель элементов массива.
Рассмотрим как использовать оба этих класса в работе с JSON-массивом на примере всё того же JSON-объекта со списком задач Google. Вначале пример использования TJSONArray без использования класса-перечислителя:
procedure Tfmain.EnumArray;
var JsonArray: TJSONArray;
    i: integer;
begin
  {получаем масиив из значения пары с названием "items"}
  JsonArray:=FJSONObject.Get('items').JsonValue as TJSONArray;
  for I := 0 to JsonArray.Size-1 do
     ShowMessage((JsonArray.Get(i) as TJSONObject).Get('title').JsonValue.Value)
end;

Так как мы уже знаем, что массив содержится в «items», то в приведенной выше процедуре мы воспользовались перегруженным методом Get у TJSONObject и получили массив из значения пары по её названию. После того как метод Get вернул нам значение TJSONValue мы привели это значение к типу TJSONArray и тем самым получили возможность использовать свойства и методы нового класса.
Далее для установки границ цикла мы воспользовались свойством Size у TJSONArray, которое возвращает нам количество элементов массива.
Так как каждый элемент нашего массива — это объект, то в цикле мы приводим каждый элемент массива к типу TJSONObject.
Далее, для примера, я вывел для каждого элемента массива значение title — заголовка задачи.

Опять же обращу внимание на то, что использовал выбор значения пары по имени только потому, что 100% знал, что такая пара в объекте присутствует, если бы я разбирал объект с заранее неизвестным составом пар, то воспользовался бы выборкой по индексу (см. процедуру парсинга свойств для класса TTaskResource).
Теперь посмотрим как используется перечислитель TJSONArrayEnumerator и закончим наш пример разбора JSON-объекта с задачами:

procedure Tfmain.EnumArray2;
var JsonArray: TJSONArray;
    Enum: TJSONArrayEnumerator;
    Task : TTaskResource;
begin
  {получаем масиив из значения пары с названием "items"}
  JsonArray:=FJSONObject.Get('items').JsonValue as TJSONArray;
  {создаем перечислитель}
  Enum:=TJSONArrayEnumerator.Create(JsonArray);
  {перебираем все элементы массива}
  while Enum.MoveNext do
    begin
      Task:=TTaskResource.Create;
      {передали значение в метод для парсинга}
      Task.ParseJSON(Enum.GetCurrent);
      Task.Free;
    end;
end;

В этом примере мы создали перечислитель типа TJSONArrayEnumerator, передав в качестве параметра конструктора полученный из JSON-объекта массив, а затем, воспользовавшись в цикле While методом MoveNext перечислили все элементы массива, передав их в метод для заполнения свойств класса, который мы рассматривали выше.
Для получения текущего элемента массива можно использовать либо метод GetCurrent (как это делается в примере выше), либо использовать свойство объекта Current.
На этом про чтение данных из JSON-объекта можно закончить и перейти к следующей части — записи данных в формате JSON.

Запись данных

Рассмотрим абстрактный пример, в котором запишем в JSON-объект все возможные типы данных (строки, числа и т.д.).

procedure Tfmain.Button2Click(Sender: TObject);
var JSONObject, InnerObject : TJSONObject;
    Pair : TJSONPair;
    JsonArray: TJSONArray;
    S:TStringList;
begin
  S:=TStringList.Create;
  {создали объект верхнего уровня}
try
  JSONObject:=TJSONObject.Create;
  {создали пару}
  Pair:=TJSONPair.Create('stringPair','TestString');
  {записали пару в объект}
  JSONObject.AddPair(Pair);
  {можно записать и так}
  JSONObject.AddPair(TJSONPair.Create('stringPair2','TestString2'));
  {и так}
  JSONObject.AddPair(TJSONPair.Create('NumberPair2',TJSONNumber.Create(128)));
 
  {добавляем в объект ещё один объект}
  InnerObject:=TJSONObject.Create;
  InnerObject.AddPair('Inner_StringPair','Hello World!');
  JSONObject.AddPair(TJSONPair.Create('InnerObject',InnerObject));
 
  {записываем в объект массив}
  //создали пустой массив
  JsonArray:=TJSONArray.Create();
  JsonArray.Add('StringElement');//первый элемент - строка
  JsonArray.Add(True); //второй элемент - True
  JsonArray.Add(100500); //третий элемент - число
  //четвертый элемент - объект
  JsonArray.AddElement(TJSONObject.Create(TJSONPair.Create('PairName','PairValue')));
 
  //записали массив в объект
  JSONObject.AddPair('Array',JsonArray);
 
  //сохраняем объект в файл
  S.Add(JSONObject.ToString);
  S.SaveToFile('json.txt');
finally
  S.Free;
  JSONObject.Destroy;
end;
end;

В представленном выше примере я постарался привести все возможные варианты записи JSON-объекта, а именно:

  1. Запись строки
  2. Запись числа
  3. Запись булевых значений
  4. Запись массива в котором каждый элемент содержит различные типы данных — строку,  True, число, json-объект

Как можно видеть по примеры, вариантов записи данных масса, на в основе всей записи находится объект (TJSONObject) у которого есть несколько перегруженных методов AddPair для записи пар:

function AddPair(const Pair: TJSONPair): TJSONObject; overload;
function AddPair(const Str: TJSONString; const Val: TJSONValue): TJSONObject; overload;
function AddPair(const Str: UnicodeString; const Val: TJSONValue): TJSONObject; overload;
function AddPair(const Str: UnicodeString; const Val: UnicodeString): TJSONObject; overload;

Как нетрудно догадаться, т.к. AddPair возвращает нам TJSONObject, то запись объекта можно было бы осуществить и так в одну строку:

JSONObject.AddPair(Pair).AddPair(TJSONPair.Create('stringPair2','TestString2'));

Для удаление пар из объекта также существует метод:

function RemovePair(const PairName: String): TJSONPair;

В целом по записи можно сказать, что модуль DBXJSON.pas позволяет проводить запись JSON-объектов любой сложности (хотя, кто бы в этом сомневался). В итоге выполнения представленного выше метода в файл был записан вот такой объект:

{"stringPair":"TestString",
 "stringPair2":"TestString2",
 "NumberPair2":128,
 "InnerObject":{"Inner_StringPair":"Hello World!"},
 "Array":["StringElement",
          true,
          100500,
          {"PairName":"PairValue"}
         ]
}

Вот, в принципе, все, что можно для начала рассказать про работу с JSON в Delphi. Естественно, что сегодня я рассмотрел далеко не все возможности работы, но и этой информации будет вполне достаточно, чтобы, например, сделать компонент или программу для работы с такими API как:

  1. Google Tasks API
  2. API Яндекс.Метрики
Или использовать JSON при работе с DataSnap.
Скачать исходник: Исходники —> XML и JSON в Delphi

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
42 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Виталий
Виталий
17/10/2011 13:26

Спасибо, очень во-время. А то я уже начал протокол криво делать — передаю данные по сети в виде таблицы, значения которой разделены табуляцией. Приступаю к переделке :).

Виталий
Виталий
17/10/2011 18:58

Я как раз столкнулся с необходимостью давать значениям имена, а то сложно как-то без них.
Вопрос по статье: а почему JSONObject.Destroy, а не JSONObject.Free? 

Виталий
Виталий
17/10/2011 19:48

Опечатки сюда или на почту?

ter
ter
17/10/2011 19:56

имхо че то интересней чем SuperObject :)
буду свой клиент для myshows.ru переписывать дак попробую сделать на FMX & dbxJson вместо VCL & SuperObject
хорошая статья (:

Сергей
Сергей
22/10/2011 12:24

Спасибо большое! Возникла необходимость в JSON, а тут Вы со своей статьей. Дай бог Вам здоровья.

Виталий
Виталий
22/10/2011 20:16

 
Почему на кавычках спотыкается?
FJSONObject := TJSONObject.ParseJSONValue(‘{«name»:»va»lue»}’)as TJSONObject;
 

Виталий
Виталий
22/10/2011 20:19

Почему на кавычках спотыкается?
[code]FJSONObject := TJSONObject.ParseJSONValue('{"name":"va"lue"}')as TJSONObject;[/code]

Сергей
Сергей
26/10/2011 11:03

Демо-пример не работает в Delphi XE, нет таких классов.

VolRus
VolRus
28/10/2011 01:28

Как раз смотрел API ubuntu one смотрю используется JSON думаю загляну ка я в поиск на webdelphi, а тут глазам не поверил первая статья и о JSON. Забавно получилось )))

Дмитрий
Дмитрий
03/11/2011 01:36

у меня почему-то только 2 перезагруженных метода ParseJSONValue для работы с байтами, а со строками нет
RAD Studio 2010 Pro
в чем проблема?

ALM
ALM
05/12/2011 20:22

Присоединяюсь к Сергею по поводу неработы примера в Delphi XE: нету класса TJSONArrayEnumerator. Просмотрел хелп — нигде такого нету. Поиск по сайте Embarcadero тоже ничего не дал.
А за статью — спасибо!

Akella
18/04/2012 15:26

Delphi XE2

var
JSONObject: TJSONObject;
Stream: TStream;
s: string;
begin


s := MyStreamToString(Stream);
// получаем в s значение {«iMaxSymbolsAD»:»248″}

JSONObject.ParseJSONValue(s);//парсим

if JSONObject.Size <= 0 then exit;// почему-то здесь ноль

Akella
18/04/2012 15:29

// получаем в s значение
[code]{"iMaxSymbolsAD":"248"}[/code]

dedoki
dedoki
11/05/2012 17:18

Хотел вот что спросить: как создать вот такой массив:
[code]Array:[
{"1":1_1,"1_2_1":1_2_2},
...,
][/code]
?
Делаю так:
[code]JSONObject:=TJSONObject.Create;
JSONArray:=TJSONArray.Create();
...
JSONArray.AddElement(TJSONObject.Create(TJSONPair.Create('1','1_1')));
JSONArray.AddElement(TJSONObject.Create(TJSONPair.Create('1_2_1','1_2_2')));
JSONObject.AddPair('Array',JSONArray);[/code]

Получаю:
[code]{
"Array":[
{"1":"1_1"},{"1_2_1":"1_2_2"}
]
}[/code]

Isaev
Isaev
18/03/2013 07:48

а в JSON выгрузка кирилицы в виде «\u043f\u0435\u0440\u0435\u043a\u0430\u0447» это как-то стандартными средствами возможно перекодировать или свой декодер писать придётся?

Isaev
Isaev
18/03/2013 18:46

Vlad, нашёл уже решение, спасибо. в XE тоже работает. примерно так:
LJSONValue:=TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(Str),0);
Str:=LJSONValue.ToString;

Isaev
Isaev
18/03/2013 22:25

Проблема с Enumerator возникла) его не было его в DelphiXE видимо?

Isaev
Isaev
19/03/2013 00:01

и как вы используете Task.ParseJSON, если ParseJSON в Private?

Graf
Graf
30/05/2013 15:56

// Может не теме но полезно
// Если нужно серверу отсылать строку с русскими символами в виде {«field1″:»u0411u0443u043au0432u044b u043fu043eu043bu044f»}
function JSONObject_ToString_Utf8(JSONObject:TJSONObject):string; // перевести текст JSON в понятный вид для сервера
var
Str: string;
Length: Integer;
StringArray: TBytes;
begin
try
result:=»;
SetLength(StringArray, JSONObject.EstimatedByteSize);
Length:=JSONObject.ToBytes(StringArray, 0);
result := StringOf(StringArray);
SetLength(result, Length);
except
result:=JSONObject.ToString;
end;
end;

Artur
Artur
24/07/2013 12:25

A kak meniat znacenia elementov v Jsone?

Isaev
Isaev
07/07/2014 21:01

А если ответ получаем с экранированными символами и вложенными объектами, то JSONObject парсит только первый уровень, а дальше не справляется, т.к. слеши мешают распознанию
Есть стандартное средство борьбы с этим. чтобы велосипед не изобретать?

Isaev
Isaev
10/07/2014 05:49
Ответить на  Isaev

Тут описал подробнее, кто знает ответ, милости прошу к обсуждению)

Игорь
Игорь
24/09/2014 03:01

Вечер добрый stackoverflow.com Писал прогу для ВоТ. Вывод статистики по игроку, по технике. Там есть апи, все данные идут в формате Json. Написал уже половину. парсил с помощью regexpr. Как и следовало ожидать — время и нагрузка на память — бешеные. скачал SuperObject. но после уже 12 часов сидения мозг не варит. Так вот — кратко. в ссылке — мой вопрос на stackoverflow.com. Не могу никак разобраться с структурой. 1 вариант — там не могу понять — как в цыкле вытянуть из мемо значения wins battles mark_of_mastery и and tank_id. вот во втором варианте — нужно получить пары и записать… Подробнее »

Игорь
Игорь
25/09/2014 08:41

Спасибо за очень доходчивый материал! SuperObject — забросил, DBXJSON — разобрался, научился наконец путешествовать по объектам и парам.
Теперь еще 1 вопрос — нет ли у Вас статьи по TThreads. А то у меня штук 10 парсеров в программе, данные тянутся через idHttp в формате JSON. хотелось бы почитать по синхронизации и CriticalSection. В сети много информации, даже 2 видео пересмотрел с «профи» типа меня, которые создают проги с многопоточностью. Но — очень все поверхностно.

Игорь
Игорь
25/09/2014 16:06
Ответить на  Vlad

Спасибо за ссылку! Супер материал!

noisy
noisy
27/09/2014 18:48

Переводим русский текст ‘должно’ к виду \u0434\u043e\u043b\u0436\u043d\u043e функция работает аналогично PHP function StrToUTF16(const Str: String): String; const HexMap : array [0..15] of WideChar = ('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'); function ChrToUTF16(const ChrCode: Integer): String; inline; begin Result := '\u' + HexMap[ChrCode shr 12] + HexMap[(ChrCode shr 8) and 15] + HexMap[(ChrCode shr 4) and 15] + HexMap[ChrCode and 15]; end; var Tmp: PWideChar; begin Result := ''; if Str = '' then Exit else Tmp := PWideChar(Pointer(Str)); while Tmp^ #0 do begin case Tmp^ of #1..#31: case Tmp^ of #8 : Result := Result + '\b'; #9 : Result := Result + '\t'; #10:… Подробнее »

trackback

[…] последний раз я более менее подробно рассказывал о работе с JSON в Delphi года три назад, когда актуальной была Delphi XE2. Однако […]

Артём
Артём
18/01/2017 03:42

Подскажите как разобрать ответ полученный от Synapse.

if client.HTTPMethod(‘POST’, ‘https://httpbin.org/post’) then
begin
json := TJSONObject.ParseJSONValue(MemoryStreamToString(client.Document)) as TJSONObject;
// …
end

// …

function TForm1.MemoryStreamToString(M: TMemoryStream): string;
begin
SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;

Говорит:
[DCC Error] Unit1.pas(73): E2250 There is no overloaded version of ‘ParseJSONValue’ that can be called with these arguments

Delphi 2010 стоит.

Артём
Артём
19/01/2017 03:47

Зачем использовать для работы с сетью тупой паскаль, когда вокруг полно других более подходящих для этой задачи языков — php, python и др.

Sergienko Vitaly
20/03/2018 05:19

Однозначно спасибо за статью!

>>Открыв модуль DBXJSON.pas Вы можете обнаружить там следующие классы
Пропишите, может в скобочках, в Delphi 10.1 подключать нужно JSON
В модуле «DBXJSON.pas» класса TJSONObject теперь нет. Кому-то чуть сбережёт нервы )))