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

В прошлый раз была разминка. Прочитали несколько узлов — запомнили и успокоились. Сегодня задачка будет по-сложнее — разбор элементов Entry в Google Data Feed. В начале небольшой экскурс в мануалы по Google Data Protocol v.2.0 в часть, касающуюся проблемной области.

Итак, элементы Entry — это по сути хранилище всевозможных данных для работы со всеми известными API, использующими в своей работе Google Data Protocol. В этих элементах может содержаться всё, что угодно — от контактной информации до наборов данных Google Analytics, FeedBurner и пр.  Однако есть четыре предопределенных структуры для entry (определяются как kinds) — это:

  1. Contact kind — набор данных контакта
  2. Profile Kind — набор данных по профилю пользователя
  3. Event kind — набор данных для события
  4. Message kind — набор данных для сообщения


В каждой из этих структур выделены элементы: обязательные, необязательные и дополнительные.

Причём обязательных элементов намного меньше, чем всех других. Все элементы, непосредственно относящиеся к GData («родные» для протокола) определяются как:

gd:ххх

где ххх название элемента. В этуже схему включаются перечислители, т.е. те узлы XML, которые содержат только чётко определенные строковые аттрибуты, например элемент gd:eventStatus может содержать в атибуте Value следующие значения:

http://schemas.google.com/g/2005#event.canceled
http://schemas.google.com/g/2005#event.confirmed
http://schemas.google.com/g/2005#event.tentative

Короче, немного поковырявшись в «родных» элементах протокола можно составить список из 49 различных gd-элементов. Каждый компонент при этом может содержать как текстовую информацию, так и набор аттрибутов в т.ч. перечисляемого типа, integer, boolean и т.д. «Гадость» заключается в том, что отдельные элементы, например gd:feedLink может содержать в себе точно такой же Feedб кокой разбирается в текущий момент, а этот фид опять же может пестрить элементами entry и т.д. и т.п. Короче сходу так просто и не въедешь в тему откуда ноги произрастают у данных. Собственно, отчасти поэтому, отчасти по другой причине и начал разбирать XML в TreeView.
Помимо всего прочего протокол не запрещает размещать внутри Entry и другие элементы API, например элементы gCal:xxx — определяющие данные для Календаря Google и т.д. Как вариант, можно было бы оставить все как есть, т.е. «выдирать» из фида необходимую информацию, работать с ней и на этом успокоится. Но, мы не будем полагаться на случай (с). Итак, что «умеет» на текущий момент модуль для работы с GData.
Первое: разбирает Feed и выделяет основные элементы фида, отдельно сохраняя все элементы Entry. При этом можно провести обратную процедуру — передать набор элементов в класс и собрать XML-документ для отправки на сервер.
Второе: в части работы с Entry. Работа ведется следующим образом:

1. В каждом элементе Entry определяются как и в Feed корневые элементы, относящиеся непосредственно к узлу, например автор записи, даты публикации и обновления и т.д.

2. Все оставшиеся элементы фильтруются и выводится список элементов gd-элементов, имеющий следующий вид:

type
TGDElement = record
  ElementType : TgdEnum;
  XMLNode: IXMLNode;
end;
 
type
  PGDElement = ^TGDElement;
 
type
TGDElemntList = class(TList)
private
  procedure SetRecord(index: Integer; Ptr: PGDElement);
  function GetRecord(index: Integer): PGDElement;
public
  constructor Create;
  procedure Clear;
  destructor Destroy; override;
  property GDElement[i: Integer]: PGDElement read GetRecord write SetRecord;
...
end;

3. Оставшиеся элементы пока в расчёт не беруться, т.к. у них опять же будут свои структуры, атрибуты и т.д.

4. Любой элемент из списка TGDElemntList можно обработать соответсвующие функцией и уже из IXMLNode получить структуру Delphi (record, class), с которой можно делать всё, что угодно: править, дополнять и т.д. Если не нужна структура — не проблема — можно работать непосредственно с узлом IXMLNode.

Например, так происходит обработка одного из узлов в entry:

function gdAdditionalName(aXMLNode: IXMLNode): TgdAdditionalNameStruct;
begin
  if GetGDNodeType(aXMLNode.NodeName) <> ord(egdAdditionalName) then
    raise Exception.Create(Format(rcErrCompNodes,[cGDTagNames[ord(egdAdditionalName)]]));
try
  if aXMLNode.Attributes['yomi'] <> null then
  Result.yomi := aXMLNode.Attributes['yomi'];
  Result.Text := aXMLNode.Text;
except
  raise Exception.Create(Format(rcErrPrepareNode, [aXMLNode.NodeName]));
end;
end;

Здесь мы берем узел gd:AdditionalName и представляем его в виде структуры:

type
TgdAdditionalNameStruct = record
  yomi: string; //атрибут узла, означающий псевдоним пользователя
  Text: string; //текстовая часть узла - имя
end;

Аналогичным образом идёт обработка и более сложных узлов, например, содержащих внутри себя ещё ряд узлов gd:xxx.

Для конечного пользователя, которому лень смотреть исходник опять же всё умещается в несколько строк кода. Возвращаясь к примеру выше получение структуры TgdAdditionalNameStruct в вызывающей программе будет может быть таким:

var Node: IXMLNode;
    Struct: TgdAdditionalNameStruct;
begin
...
  Struct:=gdAdditionalName(Node)
...
end;

Или используя любой цикл перечислить все узлы списка и перебрать все структуры, но это, думаю будет немного лишним.

В настоящий момент дописываю работы с gd-элементами в фиде. Слудующий шаг — обратная процедура: по предоставленным данным собрать фид и скинуть на сервер. Ну и, конечноже, более плотная работа с Google Celendar API.

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии