WordPress. Работа с XML-RPC в Delphi. Комментарии (продолжение)

Источник: webdelphi

Источник: WebDelphi

В прошлый раз я рассматривал процедуру получения комментариев из блога WordPress с использованием XML-RPC.

Сегодня продолжим разбираться с вопросами использование структур XML-RPC в Delphi и немного "приукрасим" нашу Delphi-функцию по чтению комментариев.

Как вы помните, любая структура (struct) в XML-RPC имеет следующее содержание:

- <struct>
- <member>
 <name>название</name>
- <value><int>значение</int></value>
 </member>

то есть каждый элемент имеет свое название и значение. Первое, что приходит на ум в плане интерпретации этого кода в Delphi - создать динамический массив записей (record). Например таких:

1
2
3
4
5
6
7
8
9
type
TSimpleType = (tsInt, tsI4, tsString, tsDouble, tsDateTime, tsBase64, tsBoolean);
 
type
TStructElement = packed record
  Name : string;
  SType: TSimpleType;
  Value: string;
end;

Таким образом, мы всегда можем определить какой тип данных содержит член структуры и правильно его записать в XML-документ.

Пока остановимся на этом варианте. Функция добавления структуры в уже созданный XML-документ может быть такой:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
procedure TBlog.SetStructure(Struct: TStructArray; Document: PXMLDocument);
var i:integer;
     Root,Member: IXMLNode;
begin
if (Length(Struct)=0) or(Document^.IsEmptyDoc) then Exit;
Root:=Document^.DocumentElement.ChildNodes.FindNode('params').AddChild('param').AddChild('struct');
for i:= 0 to Length(Struct) - 1 do
  begin
    member:=Root.AddChild('member');
    member.AddChild('name').NodeValue:=Struct[i].Name;
    case Struct[i].SType of
       tsInt,tsI4:member.AddChild('value').AddChild('int').NodeValue:=Struct[i].Value;
     tsString:  member.AddChild('value').AddChild('string').NodeValue:=Struct[i].Value;
     tsDouble:  member.AddChild('value').AddChild('double').NodeValue:=Struct[i].Value;
     tsDateTime:member.AddChild('value').AddChild('dateTime.iso8601').NodeValue:=Struct[i].Value;
     tsBase64:  member.AddChild('value').AddChild('base64').NodeValue:=Struct[i].Value;
      tsBoolean: member.AddChild('value').AddChild('boolean').NodeValue:=Struct[i].Value;
    end;
  end;
end;

Признаться, был позыв сделать запись содержащую поле типа Variant и избавиться от TSimpleType, но что-то я засомневался по поводу верной интерпретации полей типа boolean. Не будет ли в случае задание булевой переменной в виде 0-1 программа записывать в документ поле структуры с типом int?

Чтобы избежать подобных недоразумений пришлось использовать лишнее поле и на основании его записывать данные в XML-документ.

Теперь вернемся к нашей процедуре чтения комментариев. В прошлый раз мы остановились на том, что использовали в качестве одного из параметров отдельной записи record, описывающей поле filter в запросе. еперь процедуру можно немного видоизменить и включить во входные параметры наш новый тип данных.

У меня, после недолгих преобразований, получилась следующая процедура для чтения комментариев из блога WordPress:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function TBlog.GetComments(const CommentStruct: TStructArray): TComments;
var i,j:integer;
  Doc:  IXMLDocument;
  Values: IDOMNodeList;//все тэги value массива
  Members: IDOMNodeList;//все тэги member элемента value
  List: TStringList;
begin
  Doc:=GetDocument('wp.getComments');
  SetParam(tsInt,'1',@Doc);
  SetParam(tsString,FUserName,@Doc);
  SetParam(tsString,FPassword,@Doc);
  SetStructure(CommentStruct,@Doc);
  SendQuery(@Doc,FURL);
  Values:=Doc.DOMDocument.getElementsByTagName('data').item[0].childNodes;
  SetLength(Result,Values.length);
for i:= 0 to Values.length-1 do
  begin
    Members:=Values[i].firstChild.childNodes;//получили все members для 1 value
    for j:=0 to Members.length - 1 do
       begin
         with Result[i]do
           begin
             case j of
               0:Result[i].date_created_gmt:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               1:Result[i].user_id:=StrToInt((Members[j].lastChild.firstChild as IDOMNodeEx).text);
             2:Result[i].comment_id:=StrToInt((Members[j].lastChild.firstChild as IDOMNodeEx).text);
               3:Result[i].parent:=StrToInt((Members[j].lastChild.firstChild as IDOMNodeEx).text);
               4:Result[i].status:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               5:Result[i].content:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               6:Result[i].link:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               7:Result[i].post_id:=StrToInt((Members[j].lastChild.firstChild as IDOMNodeEx).text);
               8:Result[i].post_title:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               9:Result[i].author:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               10:Result[i].author_url:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               11:Result[i].author_email:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
               12:Result[i].comment_type:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;
         end;
     end;
  end;
end;
end;

Напомню, что тип TComments - это динамический массив записей вида:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type
TComment = packed record
  date_created_gmt: string;
  user_id: integer;
  comment_id: integer;
  parent: integer;
  status: string;
  content: string;
  link  :string;
  post_id: integer;
  post_title: string;
  author: string;
  author_url: string;
  author_email: string;
  author_ip : string;
  comment_type : string;
end;

Двигаемся дальше. С одной стороны все вроде бы замечательно - создали переменную типа TStructArray, передали в качестве параметр процедуры и получили ответ. Но с другой стороны - что делать если в запросе должна быть структура на 10 полей? 20? Это ж замаешься для каждого поля указывать название, тип, значение. Я решил эту проблему следующим образом (пока черновой вариант). Создаем функцию для создания struct на определенный запрос. В нашем случае это wp.GetComments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function TBlog.GetCommentStructure(post_id: integer; status: string; number,
offset: integer): TStructArray;
begin
  Result:=nil;
  if post_id>-1 then
    begin
      Setlength(Result,length(Result)+1);
      Result[length(Result)-1].Name:='post_id';
      Result[length(Result)-1].SType:=tsInt;
      Result[length(Result)-1].Value:=IntToStr(post_id);
    end;
if length(status)>0 then
  begin
    Setlength(Result,length(Result)+1);
    Result[length(Result)-1].Name:='status';
    Result[length(Result)-1].SType:=tsString;
    Result[length(Result)-1].Value:=status;
  end;
if number>-1 then
  begin
    Setlength(Result,length(Result)+1);
    Result[length(Result)-1].Name:='number';
    Result[length(Result)-1].SType:=tsInt;
    Result[length(Result)-1].Value:=IntToStr(number);
  end;
if offset>-1 then
  begin
    Setlength(Result,length(Result)+1);
    Result[length(Result)-1].Name:='offset';
    Result[length(Result)-1].SType:=tsInt;
    Result[length(Result)-1].Value:=IntToStr(offset);
  end;
end;

и уже результат этой функции используем для получения комментариев:

1
2
3
4
function TBlog.LoadComments(const Post_id: integer; Numder, Offset: integer; Status: string): TComments;
begin
  Result:=GetComments(GetCommentStructure(Post_id,Status,Numder,Offset));
end;

При этом, если задать параметрам типа integer значения -1, а в параметре статус передать пустую строку, то функция вернет комментарии из блога по умолчанию, т.е. последние 10 одобренных.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=23390