DeepEdit!

Программирование баз данных на Oracle, техническая документация, литература, статьи и публикации

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Средство просмотра JSON в Delphi

Павел Гловацки (Pawel Glowacki)

Поддержка JSON была внедрена в Delphi 2010 как часть архитектуры драйвера баз данных DBExpress, но естественно она не ограничивается использованием только в приложениях баз данных. Формат JSON схож с XML: оба предназначены для обмена данными в текстовой форме. Для упрощения работы с XML-документами в Delphi 6 был реализован компонент TXMLDocument, а также мастер XML Data Binding Wizard.
В этой статье я представлю аналогичный компонент для работы с JSON под названием "TJSONDocument". Следующим шагом будет реализация компонента "TJSONTreeView" для отображения содержимого "TJSONDocument" в VCL-приложении. В этой статье будет рассмотрено создание простого приложения для просмотра данных формата JSON на основе данных компонентов. Для работы с XML существует две категории синтаксических анализаторов (parser): DOM (Document Object Model) и SAX (Simple API for XML).
DOM-анализатор считывает строки формата XML и строит соответствующее представление документа в памяти, которое приложение может обходить и изменять.
С другой стороны, SAX - это потоковый интерфейс - приложения получают информацию из XML-документов непрерывным потоком, без возможности возврата или навигации. В конце этой статьи будет описан компонент "TJSONParser", созданный на основе TJSONDocument, реализующий SAX-модель обработки JSON[1].
Почему JSON?
Формат JSON является относительно новым и впервые был описан Дугласом Крокфордом (Douglas Crockford) и опубликован IETF в RFC-4627 "The application/json Media Type for JavaScript Object Notation" [2] в июле 2006 года.
Во многом JSON похож на XML - оба являются текстовыми форматами для обмена данными и широко используются в сети Интернет. В отличие от XML, который к настоящему моменту стал целым семейством стандартов вроде пространства имен XML Namespaces, XML Schema, XSL, XPath и других, JSON определяет лишь малый набор правил форматирования для представления структурированных данных. Ключевое преимущество JSON - его простота. Дуглас Крокфорд описал структуру JSON в своем докладе, представленном на Конференции XML 2006 года в Бостоне "JSON: The Fat-Free Alternative to XML" [3]: типы данных, представленные в JSON, - это строки, числа, логические значения, объекты, массивы, и пустые значения (NULL). Синтаксис JSON наглядно представим в виде следующей диаграммы:
JSON стал X в Ajax. В настоящее время это предпочитаемый формат данных для приложений, использующих Ajax. Наиболее распространенный способ - использование JSON с XMLHttpRequest. При получении текст ответа может быть быстро преобразован в структуру данных JavaScript, и обработан в приложении.
Синтаксис JSON значительно проще чем XML, поэтому его обработка более эффективна.
JSON не имеет пространств имен. Каждый объект сам является пространством имен: его набор ключей не зависит от других объектов, даже вложенность не учитывается.
JSON использует контекст, чтобы избежать двусмысленности, как и обычные языки программирования.
JSON не имеет средств проверки. Быть правильно сформированным и допустимым - это не одно и то же, чтобы быть корректным и актуальным. В конечном счете, каждое приложение само отвечает за проверку входных данных.
Ниже приведен фрагмент текста формата JSON, основанный на "Sample Konfabulator Widget" из [5], который использован в последующих частях данной статьи.
{
"widget":   {
"debug":   "on", "window":   {
"title":   "Sample Konfabulator Widget",
"name":   "main_window",
"width":  500,
"height":  500
},
"misc":   ["hello",  23,  false]
}

Delphi и DBXJSon.pas
Многие языки программирования имеют встроенную поддержку JSON или имеют библиотеки для работы с JSON. Эти JSON библиотеки для различных языков программирования, представлены на странице JSON [4], в том числе три библиотеки для Delphi с открытым исходным кодом. Начиная с Delphi 2010, поддержка JSON включена в библиотеку VCL и реализована в модуле DBXJSON.pas.
Чтобы визуализировать классы, отвечающие за поддержку JSON в Delphi, я подключил модуль "DBXJSON" в небольшое тестовое приложение, переключился на вкладку "Model Support" в менеджере проектов и получил следующую UML-диаграмму классов. Некоторые из классов модуля DBXJSON.pas, не относящиеся непосредственно к поддержке JSON, здесь не показаны.

JSON имеет три простых типа данных - строки, числа и логические значения, а также два сложных типа - массивы и объекты. Строка представляет собой последовательность из нуля или более символов, заключенных в кавычки, с экранированием управляющих символов обратным слэшем.
Подобное представление используется в большинстве языков программирования. Числа могут быть представлены в виде целых, действительных, или чисел с плавающей точкой. JSON не поддерживает представления в восьмеричной или шестнадцатеричной системах исчисления. А также не имеет значений для NaN или бесконечности. Числа при этом не заключаются в кавычки.
Объект JSON представляет неупорядоченный набор пар ключ-значение. Ключи являются строками, значения могут быть одним из любых поддерживаемых JSON типов данных. Для разделения ключей и значений используется двоеточие, для разделения пар - запятая. Все описание объекта заключается в фигурные скобки. Массив JSON - это упорядоченная коллекция значений, разделенных запятыми, заключенная в квадратные скобки.
В качестве кодировки текста в JSON всегда используется Unicode. UTF-8 -единственная кодировка, имеющая смысл в сети, но также допускаются UTF-16 и UTF-32. JSON не имеет номера версии и не предполагает изменения синтаксиса в будущем.

В Delphi 2007 архитектура драйвера баз данных DBX была переделана с использованием чистого Delphi-кода, что привело к появлению некоторых интересных возможностей, включая расширенные типы команд. В последующей версии - Delphi 2009, архитектура DBX была расширена, а фреймворк DataSnap, предназначенный для построения клиент-серверных и многозвенных приложений, был переработан и стал расширением новой архитектуры DBX.
Одна из самых интересных и мощных возможностей внедренных в DataSnap в Delphi 2010 - обратные вызовы (callbacks), размещённые в методах сервера DataSnap. Это позволяет серверу выполнять код клиента. В модуле DBXJSON.pas определен абстрактный базовый класс для объектов обратного вызова, содержащий метод "Execute", который принимает и возвращает параметры типа TJSONValue. Это позволяет разработчику передавать данные туда и обратно. Они могут быть сколь угодно сложными структурами данных, представленные в виде JSON. Вот объявление данного класса:
TDBXCallback = class abstract public
function Execute(const Arg: TJSONValue): TJSONValue; virtual;  abstract;

// ... остальные члены класса пропущены 

end;

Модуль DBXJSON содержит функционал, позволяющий преобразовать текст формата JSON в набор значений (дерево) - потомков TJSONValue, а также реализовать обратное преобразование объектов в текст. Свойство TJSONAncestor.Owned (булевое значение) было внедрено, чтобы подчеркнуть тот факт, что все потомки JSON имеют свойство Owned с помощью которого контролируется время жизни объекта в памяти. Класс TJSONObject содержит статический метод ParseJSONValue, который реализует функционал синтаксического разбора JSON. Метод принимает строку формата JSON, как входной параметр, и возвращает ссылку TJSONValue-типа на корень дерева, состоящего из потомков TJSONAncestor.
Также возможно формировать текст формата JSON для представления дерева JSON объектов, используя перегруженный метод ToString для любого потомка класса TJSONAncestor.

Компонент TJsonDocument
До того, как в Delphi 2010 появился модуль DBXJSON, я пытался реализовать синтаксический анализатор самостоятельно кодированием синтаксических диаграмм JSON.
С появлением DBXJSON уже нет смысла изобретать велосипед, однако до сих пор JSON не имеет поддержки времени проектирования. Все должно быть реализовано в коде. Поэтому возникла идея создания простого VCL компонента, реализующего JSON анализатор, и использующий метод TJSONObject.ParseJSONValue, который принимает текст формата JSON и возвращает дерево объектов, представляющее соответствующую структуру JSON документа в памяти.
Компонент "TJSONDocument" был реализован в модуле "jsondoc", в соответствии названию модуля "xmldoc", реализующего класс
TXMLDocument.
Ниже представлено описание VCL-компонента TJSONDocument:
Полный исходный код этого компонента, а также и всех других исходных кодов приведенных в данной статье могут быть загружены с [1] ^м. раздел "Ссылки" в конце статьи).
Класс TJSONDocument содержит published-свойство "JsonText: string", которое может быть использовано для указания текста формата JSON для синтаксического анализа, а также public-свойство "RootValue: TJSONValue", для определения ссылки на корневой узел "TJSONValue" и создания соответствующего JSON-текста.
Присвоение значения любому из этих свойств влечет обновление другого. Событие "OnChange" вызывается всякий раз, когда данные, связанные с компонентом, изменяются.
Таким образом, это событие предоставляет другим компонентам приложения возможность получать соответствующие уведомления и обновлять свое состояние. В этом смысле компонент "TJSONDocument" может быть использован для разбора и формирования JSON, как и описано в оригинальном JSON RFC [2].
Public-свойство "IsActive: Boolean" возвращает значение True, если компонент TJSONDocument содержит корректные JSON данные, или значение False если элемент пуст.
function TJSONDocument.IsActive boolean; begin
Result    :=   RootValue   <>  nil; end ;

Метод "TJSONObject.ParseJSONValue: TJSONValue" чувствителен к содержимому текста JSON передаваемого для разбора. Если переданная строка не содержит корректный JSON-текст или содержит JSON-текст с дополнительными пробелами, то метод всегда возвращает nil. Статическая функция "StripNonJson" используется для удаления из текста JSON любого неподходящего символа и реализуется с использованием класса "TCharacter" из соответствующего модуля библиотеки VCL "Character":

class function TJSONDocument.StripNonJson(s:   string): string;
var ch:  char;  inString:  boolean; begin
Result  :=  ''; inString  := false; for ch in do begin
if ch =  '"'  then
inString  := not inString; if TCharacter.IsWhiteSpace(ch)  and not inString then
continueResult  := Result ch; end; end;

unit jsondoc

//...

type
TJSONDocument = class(TComponent) private
FRootValue: TJSONValue;
FJsonText:  string; FOnChange: TNotifyEvent;
procedure SetJsonText(const Value:  string);
procedure SetRootValue(const Value: TJSONValue); protected
procedure FreeRootValue;
procedure DoOnChange; virtual; public
class function IsSimpleJsonValue( v:  TJSONValue):
boolean;  inline; class function UnQuote(s:  string):  string;  inline; class function StripNonJson( s :  string):  string;  inline;
constructor Create( AOwner:  TComponent);  override; destructor Destroy;  override;
function ProcessJsonText:  boolean; function IsActive:  boolean; function EstimatedByteSize:  integer;
property RootValue: TJSONValue read FRootValue write SetRootValue; published
property JsonText:  string read FJsonText write SetJsonText;
property OnChange:  TNotifyEvent read FOnChange write FOnChange;
end;
Синтаксический разбор JSON реализован в методе "ProcessJsonText", который вызывается в результате присваивания значения published-свойству "JsonText: string".
procedure TJSONDocument.SetJsonText(const Value: string); begin
if FJsonText <> Value then begin
FreeRootValue; FJsonText  := Value;
if FJsonText <>       then ProcessJsonText end; end;
function TJSONDocument. ProcessJsonText:  boolean;
var :  string;
begin
FreeRootValue;
s  := StripNonJson(JsonText);
FRootValue   := TJSONObject.ParseJSONValue(BytesOf(s),0); Result  := IsActive; DoOnChange; end;
Компонент "TJSONDocument" был разработан так, чтобы быть максимально компактным. Для удобства он также реализует метод "EstimatedByteSize: Integer", предоставляемый DBXJSON. Во время разработки в инспекторе объектов Delphi 2010 компонент "TJSONDocument" выглядит следующим образом:

В дополнение к обычным возможностям средств просмотра, я добавил возможность отображения количества вложенных узлов для каждого непустого JSON объекта или массива, а также оценку размера занимаемой памяти для данного узла. Основная функциональность этого компонента реализуется с помощью его public-метода "LoadJson", который заполняет дерево на основе присоединенного "TJSONDocument" компонента.

Компонент TJsonTreeView
Я всегда хотел реализовать средство просмотра (viewer) JSON в Delphi. Компонент "TJSONDocument" не является визуальным, поэтому мне потребуется отдельный визуальный компонент, который обеспечит графическое представление JSON в виде дерева. Этот компонент должен иметь published-свойство "JSONDocumеnt", чтобы иметь возможность соединять оба компонента во время разработки.
Каким образом должны быть визуализированы JSON-данные? Будет ли достаточно использовать Delphi-компонент TTreeView, или мне потребуется реализовывать операции рисования в коде? Может быть, я должен использовать TVirtualTreeView, чтобы получить дерево с несколькими столбцами?
Хорошие вопросы, так что я решил поискать вдохновения в Интернете. В сети существуют как простые, так и сложные средства просмотра JSON. Некоторые из них - отдельные приложения. Например, разработанное для .NET приложение доступное на http://jsonviewer.codeplex.com/Другие встроены в web-станицы - такие как http://www.jsonviewer.com/ или http://jsonviewer.stack.hu/.
Больше всего мне понравилось приложение, реализованное на Java и доступное как часть проекта Apache Pivot Project[6] for Rich Internet Applications (http://pivot.apache.org/demos/json-viewer.html).
Единственная вещь, которая мне не понравилась, - то, что он сортирует свойства JSON по алфавиту и не сохраняет исходный порядок следования пар.
Ниже представлен снимок экрана страницы Apache Pivot, и это та функциональность, которую я хочу получить для основанного на TreeView приложения.
Приступим
Я решил создать свой компонент JSON TreeView в виде потомка стандартного компонента "TTreeView" библиотеки Delphi VCL. Хорошей практикой программирования в Delphi было бы наследование от "TCustomTreeView", чтобы определить какие из унаследованных protected-свойств следует определить как published. В нашем случае я хочу, чтобы пользователь имел доступ ко всей функциональности TTreeView во время разработки, поэтому не требуется прятать никакие из свойств.
unit jsontreeview;
type
TJSONTreeView = class(TTreeView)
public
procedure LoadJson; published
property JSONDocument:   TJSONDocument  // ... property VisibleChildrenCounts:  Boolean // ... property VisibleByteSizes:  Boolean // . end;
procedure TJSONTreeView LoadJson;
var v:  TJSONValue;  currNode:  TTreeNode;  i ,  aCount:  integer;
:  string; begin
ClearAll ;
if   (JSONDocument <> nil)   and JSONDocument.IsActive then begin
v  := JSONDocument.RootValue Items.Clear;
if TJSONDocument.IsSimpleJsonValue(v)   then
Items.AddChild(nil,  TJSONDocument.UnQuote(v.Value)) else if is TJSONObject  then begin
aCount   := TJSONObject(v).Size; s  := '{}';
if VisibleChildrenCounts then
s  := +  '   ('  + IntToStr (aCount)  +  ')';
if VisibleByteSizes then
s   := +   '   (size:   '  + IntToStr(v.EstimatedByteSize) +  ' bytes)';
currNode  := Items.AddChild(nil,  s);
for i  := 0 to aCount - 1 do
ProcessPair(currNode,  TJSONObject(v),   i)
end
else if is TJSONArray then begin
aCount   := TJSONArray(v).Sizes  := '[]';
if VisibleChildrenCounts then
s  := +  '   ('  + IntToStr(aCount)  +  ')';
if VisibleByteSizes then
s   := +   '   (size:   '  + IntToStr(v.EstimatedByteSize) +  ' bytes)';
currNode  := Items.AddChild(nil,  s);
for i  := 0 to aCount - 1 do
ProcessElement(currNode,  TJSONArray(v),   i)
end else
raise EUnknownJsonValueDescendant.CreateFullExpand; end; end;
procedure TJSONTreeView. ProcessPair( currNode:  TTreeNode;
obj :  TJSONObject;  aIndex:  integer); var p:  TJSONPair;  s:  string;  n:  TTreeNode;  i,  aCount:  integer; begin
p  := obj.Get(aIndex);
s   := TJSONDocument.UnQuote(p.JsonString.ToString)   +   '   :   '; if TJSONDocument. IsSimpleJsonValue( p. JsonValue)   then begin
Items.AddChild(currNode,  p.JsonValue ToString); exit; end;
if p. JsonValue is TJSONObject then begin
aCount   := TJSONObject(p.JsonValue).Size;
s  := +  '   {}';
if VisibleChildrenCounts then
s  := +  '   ('  + IntToStr (aCount)  +  ')'; if VisibleByteSizes then
s   := +   '   (size:   '  + IntToStr(p.EstimatedByteSize)   + ' bytes)'; n  := Items.AddChild(currNode,  s); for i  := 0 to aCount - 1 do
ProcessPair( n,  TJSONObject( p. JsonValue),  i);
end
else if p. JsonValue is TJSONArray then begin
aCount   := TJSONArray(p.JsonValue).Size;
s  := +  '   []';
if VisibleChildrenCounts then
s  := +  '   ('  + IntToStr (aCount)  +  ')'; if VisibleByteSizes then
s   := +   '   (size:   '  + IntToStr(p.EstimatedByteSize)   + ' bytes)'; n  := Items.AddChild(currNode,  s); for i  := 0 to aCount - 1 do
ProcessElement( n,  TJSONArray( p. JsonValue),  i);
end else
raise EUnknownJsonValueDescendant.Create;
end;
procedure TJSONTreeView. ProcessElement( currNode:  TTreeNode;
arr:  TJSONArray;  aIndex:  integer); var v: TJSONValue;  s:string;  n: TTreeNode;  i,  aCount: integer; begin
v  := arr.Get(aIndex);
s  :=  '['  + IntToStr(aIndex)  +  ']   ';
if TJSONDocument. IsSimpleJsonValue( v)   then begin
Items.AddChild(currNode,  v.ToString); exit; end;
if is TJSONObject then begin
aCount := TJSONObject( v). Size;
s  := +  '   {}';
if VisibleChildrenCounts then
s  := +  '   ('  + IntToStr(aCount)  +  ')';
if VisibleByteSizes then
s   := +   '   (size:   '  + IntToStr(v.EstimatedByteSize) +  ' bytes)';
n  := Items. AddChild( currNode,  s);
for i  := 0 to aCount - 1 do
ProcessPair( n, TJSONObject( v), i);
end
else if is TJSONArray then begin
aCount := TJSONArray( v). Size; s  := +  '   []';
n  := Items. AddChild( currNode,  s); if VisibleChildrenCounts then
s  := +  '   ('  + IntToStr(aCount)  +  ')'; if VisibleByteSizes then
s   := +   '   (size:   '  + IntToStr(v.EstimatedByteSize) +  ' bytes)'; for i  := 0 to aCount - 1 do
ProcessElement( n,  TJSONArray( v),  i);
end else
raise EUnknownJsonValueDescendant. Create;
end;
Приложение для просмотра Json
На следующем шаге я использовал компоненты "TJSONDocument" и "TJSONTreeView" для реализации простого приложения для просмотра JSON. Его функциональность минимальна. Вы можете очистить текущее содержимое, используя кнопку "Clear", также вы можете скопировать в буфер обмена текст формата JSON и вставить его в окно просмотра с помощью кнопки "Paste". Также присутствует контекстное меню для управления отображением количества дочерних узлов и их размера. Значок приложения был создан с помощью IcoFX (http://icofx.ro/непосредственно из логотипа JSON взятого с домашней страницы JSON.
Ниже приведен снимок экрана приложения во время выполнения. Просто скопируйте текст формата JSON в буфер обмена и вставьте...
Компонент TJsonParser
Компонент "TJSONDocument" можно рассматривать как реализацию
Document Object Model для JSON. А как насчет SAX для JSON? SAX - или
Simple API for XML - представляет совершенно иной подход к обработке документов. Вместо того, чтобы строить представление документа в памяти, он последовательно считывает весь документ и вызывает события для каждого встреченного синтаксического элемента (лексемы)[7]. И тогда от самого приложения зависит, какие события оно будет обрабатывать, а какие нет, что удобно, например, для поиска чего-либо в большом документе.
На основе "TJSONDocument" я попробовал создать компонент "TJSONParser", который реализует SAX-модель для обработки JSON. Надёжный SAX анализатор для JSON должен быть реализован с нуля, проводить разбор JSON-текста и вызывать соответствующие события. В моём случае он реализуется прямо поверх представления JSON в памяти. Модуль "Jsonparser" содержит следующее перечисление, определяющее различные типы лексем, которые могут быть встречены в тексте формата
JSON:

type
TJSONTokenKind =  ( jsNumber,  jsString,  jsTrue,  jsFalse, jsNull,  jsObjectStart,  jsObjectEnd,  jsArrayStart, jsArrayEnd,  jsPairStart,  jsPairEnd);
Также определен тип события TJSONTokenEvent, которое вызывается, если встречена соответствующая лексема.
type
TJSONTokenKind;
TJSONTokenEvent = procedure( ATokenKind: AContent:  string)  of object;
Класс "TJSONParser" унаследован от "TJSONDocument" и определен следующим образом:
type
TJSONParser = class( TJSONDocument) private
FOnToken: TJSONTokenEvent; FTokenList: TJSONTokenList;
procedure DoOnAddToTokenListEvent( ATokenKind:
TJSONTokenKind; AContent: string); procedure DoOnFireTokenEvent( ATokenKind:
TJSONTokenKind; AContent: string); public
constructor Create( AOwner:  TComponent);  override; destructor Destroy;  override;
procedure FireTokenEvents; procedure BuildTokenList;
procedure DoProcess( val:  TJSONValue;  aTokenProc:
TJSONTokenProc); property TokenList: TJSONTokenList read FTokenList; published
property OnToken:  TJSONTokenEvent read FOnToken write FOnToken; end;

Компонент "TJSONParser" может делать две вещи. Если вы вызываете public-метод "FireTokenEvents", он будет обходить соответствующий JSON-документ, и вызывать событие "OnToken" для каждой встреченной лексемы. Кроме того, можно сформировать список лексем в памяти, и использовать свойство "TokenList" для доступа к нему. Это может быть полезно, если мы хотим реализовать средство просмотра JSON с помощью компонента VirtualTreeView, которому необходим быстрый доступ к нижележащей структуре.
Что интересно, реализация этих методов (фактически, алгоритма обхода соответствующего документа) получилась одинаковой для обоих методов -и вызова событий, и построения списка. Чтобы избежать дублирования кода, я решил ввести параметр в алгоритм обхода, используя анонимные методы.
В модуле "jsonparser" была определена следующая сигнатура анонимного метода:
type
TJSONTokenProc = reference to procedure( ATokenKind:
TJSONTokenKind; AContent: string);

Данная сигнатура подходит для обоих private-методов:
"DoOnAddToTokenListEvent" и "DoOnFireTokenEvent", присутствующих в описании класса "TJSONParser". Реализация алгоритма обхода документа заключена в методе "DoProcess", который вызывается обоими методами "FireTokenEvents" и "BuildTokenList" следующим образом:

procedure TJSONParser. BuildTokenList; begin
if RootValue <> nil then
DoProcess( RootValue,  DoOnAddToTokenListEvent);
end;
procedure TJSONParser. FireTokenEvents; begin
if RootValue <> nil then
DoProcess( RootValue,  DoOnFireTokenEvent);
end;
procedure TJSONParser. DoOnFireTokenEvent( ATokenKind: TJSONTokenKind;
AContent:  string); begin
if Assigned( FOnToken)   then
FOnToken( ATokenKind, AContent);
end;
procedure TJSONParser. DoOnAddToTokenListEvent( ATokenKind: TJSONTokenKind;
AContent:  string); begin
FTokenList. Add( ATokenKind, AContent); end;
Таким образом, внутри рекурсивного метода "DoProcess", отсутствует дублирование кода:
procedure TJSONParser. DoProcess( val: TJSONValue; aTokenProc: TJSONTokenProc); var :  integer; begin
if val is TJSONNumber then
aTokenProc( jsNumber,  TJSONNumber( val). Value)
else if val is TJSONString then
aTokenProc( jsString, TJSONString( val). Value)
else if val is TJSONTrue then
aTokenProc( jsTrue,   'true')
else if val is TJSONFalse then
aTokenProc( jsFalse,   'false')
else if val is TJSONNull then
aTokenProc( jsNull,   'null')
else if val is TJSONArray then begin
aTokenProc( jsArrayStart,   ''); with val as TJSONArray do for i  := 0 to Size - 1 do
DoProcess( Get( i),  aTokenProc); aTokenProc( jsArrayEnd,   ''); end
Заключение
В настоящее время JSON является, пожалуй, наиболее важным форматом обмена данными из используемых. Его легко обрабатывать из-за его простоты, а данные, представленные в виде JSON, обычно занимают меньший объем, чем при использовании XML.
За последние годы XML стал целым семейством стандартов, и реализация полноценного синтаксического анализатора XML с нуля не является тривиальной задачей.
Delphi 6 стала первой коммерческой IDE на рынке с поддержкой XML в web-сервисах SOAP. В Delphi 6 также появились компонент TXMLDocument и мастер XML Data Binding, упрощающие работу с XML. JSON до сих пор не хватает чего-либо наподобие XML Schema (который обобщает кросс-платформенное представление метаданных XML). Однако JSON-эквивалент постепенно разрабатывается.
На домашней странице JSON вы можете найти ссылки на черновую версию IETF RFC "JSON Media Type for Describing the Structure and Meaning of JSON Documents" [8]. Он всё ещё не утверждён, но в будущем может стать начальной точкой для реализации мастера "Data Binding
Wizard for JSON".
В этой статье я описал средство просмотра JSON, разработанное с помощью Embarcadero Delphi 2010. Исходный код, прилагаемый к этой статье, представлен в виде двух пакетов компонентов Delphi - один времени выполнения и один времени проектирования, а также "djsonview": VCL приложение Delphi, реализующее средство просмотра JSON.

else if val is TJSONObject then begin
aTokenProc( jsObjectStart,   ''); with val as TJSONObject do for i  := 0 to Size - 1 do begin
aTokenProc( jsPairStart,
Get( i). JsonString. ToString); DoProcess( Get( i). JsonValue,  aTokenProc); aTokenProc( jsPairEnd,   ''); end;
aTokenProc( jsObjectEnd,   ''); end
else
raise EUnknownJsonValueDescendant. Create;
end;
Об авторе
Павел Гловацки (Pawet Gtowacki)
Технический руководитель Европейского отделения Embarcadero Technologies по продуктам Delphi, RAD Studio и All-Access. Ранее более 7 лет работал в качестве старшего консультанта и преподавателя Delphi в Borland Educational Services и CodeGear. Наряду с работой с региональными клиентами, он так же представляет Embarcadero в других регионах, выступая с докладами на конференциях и семинарах.
Для более подробной информации вы можете посетить блог автора по адресу
http://blogs.embarcadero.com/pawelglowacki

Компонент "TJSONParser" может быть использован в качестве начальной точки для произвольной обработки JSON на самом низком уровне фактических лексем текста JSON. Анонимные методы в Delphi - это действительно здорово!




 









jAntivirus