WordPress. Робота з XML-RPC в Delphi, Різне, Програмування, статті

Джерело:webdelphi 


Сьогодні вирішив трохи продовжити тему роботи з XML-RPC в WordPress. Як це зазвичай зі мною буває, ідея народилася в момент читання випадкового блога, заманулося поглянути на роботу з постами в блозі і, заодно, спробувати написати щось під свої потреби.


Природно програму я сьогодні не викладу, але деякі викладки, листинги та ідеї в пості будуть присутні.


Коротенько роботу з XML-RPC я розглядав в пості “XML-RPC в Delphi. Перше знайомство з WordPress зсередини. “Сьогодні спробуємо просунутися далі у своїй роботі і використовувати декілька взаємопов’язаних методів для отримання певної інформації з блогу.


Конкретизуємо мета на сьогодні: Необхідно отримати дані по постам в блозі, використовуючи доступні методи з API WordPress.


Для досягнення поставленої мети нам знадобляться наступні модулі Delphi: XMLIntf , xmldomXMLDoc і бібліотека synapce або компонент Indy idHTTP (Кому як завгодно).


1. Тестуємо з’єднання з блогом.


Думаю, що перше, що слід зробити – це перевірити коректність роботи з блогом на предмет наступних можливих помилок:


1. У блозі відключена можливість використання XML-RPC


2. Користувач надав некоректні дані (url, логін або пароль).


Для перевірки можливості роботи з XML-RPC в блозі достатньо скористатися методом demo.sayHello. Якщо відповіддю буде рядок “Hello”, значить все в порядку і можна приступати до наступного кроку перевірки. Для виконання цієї перевірки нам буде потрібно виконати три простенькі задачки:



Формуємо XML-документ, який повинен виглядати так:

<methodCall>

   <methodName>demo.sayHello</methodName>

     <params>

        <param>

           <value>

                <string>test</string>

           </value>

        </param>

     </params>

</methodCall>

Для цього скористаємося інтерфейсом IXMLDocument:






1

2

3

4

5

6

7

8

9

10

11

[…]

var doc: IXMLDocument; / / документ

Root: IXMLNode; / / кореневої вузол

begin

  inherited Create;

doc: = NewXMLDocument () ;/ / створюємо порожній документ

Root: = Doc.CreateElement (“methodCall”, “”) ;/ / додаємо кореневої вузол

  Doc.DocumentElement:=Root;

Root.AddChild (“methodName”). NodeValue: = “demo.sayHello” ;/ / додаємо назву методу

параметри методу

[…]


Так як сам по собі XML-документ досить простий, то я дозволив собі трохи “Похалявім” і останнім рядком коду записав відразу всі вузли та значення єдиного параметра для нашого методу.
Тепер можна відправити документ на сервер і отримати відповідь:






1

2

3

4

5

6

7

8

9

10

11

12

13

14

[…]

with THTTPSend.Create do

    begin

Doc.SaveToStream (Document) ;/ / записуємо документ в тіло запиту

      if HTTPMethod(“POST”,aURL) then

        begin

/ / Запит успішно відправлений і отримана відповідь

        end

     else

       begin

/ / Запит не вдався

       end;

    end;

[…]


Що мені подобається в Synapce, Так це те, що не потрібно зайвих “рухів” в плані заповнення заголовків Content-Length, Content-Type і пр. Звичайно ніхто не заважає заповнити всі можливі заголовки самому, але можна обійтися і так, як показав я вище – все на автоматі.
Рухаємося далі – проводимо аналіз відповіді.
Дозволю собі нагадати Вам, що вдала відправка запиту на сервер ніяк не свідчить про те, що ми успішно отримали доступ до XML-RPC блогу. Вдала відправка запиту свідчить тільки про те, що ми відправили запит і отримали відповідь, а _что_ знаходиться у відповіді помилка чи ні – ми поки не знаємо.
Щоб поки не забивати голову зайвими способами і методами парсинга відповіді від сервера, пропоную в даному випадку зупинитися на застосуванні простої перевірки:






1

2

3

4

5

[…]

Doc.LoadFromStream (Document, xetUTF_8) ;/ / записали XML-документ

if Doc.DocumentElement.ChildNodes.FindNode(“fault”)=nil then

ShowMessage (“XML-RPC працює справно”)

[…]


Відповідно до специфікації XML-RPC повідомлення про помилки міститься у вузлі з назвою fault. Отже, стосовно нашого випадку достатньо перевірити наявність такого вузла у відповідному XML-документі – Якщо його немає, то значить перевірка пройшла успішно, був сформований коректний запит і XML-RPC працює справно.
Переходимо до наступного кроку – перевірці на коректність наданих даних користувачем і можливості роботи користувача з XML-RPC блогу.
З XML-RPC блогу має право працювати тільки адміністратор, отже, необхідно дізнатися хто пробує отримати доступ. Для цього скористаємося методом wp.getUsersBlogs. Параметрами методу є логін і пароль.
Але перш, ніж приступимо до відправки запиту і отримання відповіді, думаю, варто трохи задуматися про майбутнє і передбачити роботу з помилками, формування документів і т.д.
У попередній перевірці, можна сказати, було баловство – найпростіших варіант роботи типу:
відправив / отримав / тут_же_разобрал / забув / пошел_дальше.
Так як я планую розвивати модуль по роботі з API WordPress і далі, то є сенс визначитися з наступними моментами в роботі:


1. Сформувати “скелет” документа


2. Записати в документ усі необхідні параметри, враховуючи типи даних


3. Надіслати запит і отримати відповідь від сервера


4. Проаналізувати відповідь і, якщо у відповіді міститься повідомлення про помилку, то правильно його прочитати


Всі ці чотири кроки я зробив окремими методами класу. Під “скелетом” документа я розумію наступне вміст:

<methodCall>

 <methodName>MethodName</methodName>

 <params>    </params>

</methodCall>


Тобто частина документа, що містить ім’я методу і вузол params без вмісту. Далі на залишиться тільки правильно заповнити список параметрів. Чим ми зараз і займемося.


Всього в XML-RPC передбачено використання шести простих типів даних:

1. int і i4 – цілі чіслаinteger)

2. double – дробові числа

3. string – рядки

4. base64 – закодована рядок

5. dateTime.iso8601 – дата / час

6.    boolean


Заводимо новий тип даних:






1

TSimpleType = (tsInt, tsI4, tsString, tsDouble, tsDateTime, tsBase64, tsBoolean);

 


За допомогою значень цього типу будемо визначати тег для значення параметра.


Так як операції створення “скелета” документа і додавання параметрів методу рознесені по різних функцій, то створимо ще один допоміжний тип даних:






1

PXMLDocument = ^IXMLDocument;

 


Тепер сам метод додавання параметра в документ:






1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

procedure TBlog.SetParam(SimpleType: TSimpleType; Value: string;

Document: PXMLDocument);

var Root: IXMLNode;

begin

if Document ^. IsEmptyDoc then Exit ;/ / документ порожній

  Root:=Document^.DocumentElement.ChildNodes.FindNode(“params”);

if Root = nil then Exit; / / вузол не знайдено

  case SimpleType of

    tsInt:Root.AddChild(“param”).AddChild(“value”).AddChild(“int”).NodeValue:=Value;

    tsI4:Root.AddChild(“param”).AddChild(“value”).AddChild(“i4”).NodeValue:=Value;

    tsString:Root.AddChild(“param”).AddChild(“value”).AddChild(“string”).NodeValue:=Value;

    tsDouble:Root.AddChild(“param”).AddChild(“value”).AddChild(“double”).NodeValue:=Value;

    tsDateTime:Root.AddChild(“param”).AddChild(“value”).AddChild(“dateTime.iso8601”).NodeValue:=Value;

    tsBase64:Root.AddChild(“param”).AddChild(“value”).AddChild(“base64”).NodeValue:=Value;

    tsBoolean:Root.AddChild(“param”).AddChild(“value”).AddChild(“boolean”).NodeValue:=Value;

  end;

end;


Цей метод працює тільки в разі запису простого типу. При роботі зі структурами необхідно доопрацювати алгоритм.


Тепер про аналіз повідомлень про помилку. Розглянемо приклад того, як виглядає повідомлення про помилку в XML-RPC:

<methodResponse>

<fault>

  <value>

    <struct>

      <member>

        <name>faultCode</name>

        <value>

            <int>403</int>

        </value>

      </member>

      <member>

        <name>faultString</name>

        <value>

          <string>Bad login/pass combination.</string>

        </value>

      </member>

  </struct>

</value>

</fault>

</methodResponse>


Повідомлення про помилку приходить нам в структурі. Причому, якщо вважати, що теги member нумеруються від нуля, то кожен парний елемент структури – це код помилки, а непарний – текст помилки. Отже метод обробки повідомлень про помилку може виглядати так:






1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

function TBlog.ParseErrors(aDocument: PXMLDocument): TStringList;

var i:integer;

List: IDOMNodeList;

code: string;

begin

  List:=aDocument^.DOMDocument.getElementsByTagName(“member”);

  Result:=TStringList.Create;

  for i:=0 to List.length-1 do

    begin

      case i mod 2 of

0: code: = (List.item [i]. LastChild.firstChild as IDOMNodeEx). Text; / / парний елемент – читаємо код помилки

1 :/ / непарний елемент – читаємо текст помилки і записуємо результат

          Result.Add(code+” “+(List.item[i].lastChild.firstChild as IDOMNodeEx).text);

      end;

    end;

end;


Тут код і текст помилки записується в TStringList. Думаю, що при необхідності можна легко зробити, щоб код і текст читалися в різні списки або масиви. Нам поки що це не потрібно.


Відправку документа ми вже розглядали, тому відразу привожу метод перевірки даних на коректність:






1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

function TBlog.CheckUserAccess(const aURL, aUser, aPassword: string;var Error:string): boolean;

var Doc:IXMLDocument;

begin

Doc: = GetDocument (“wp.getUsersBlogs”); / / створили “скелет”

/ / Додаємо параметри

  SetParam(tsString,aUser,@Doc);

  SetParam(tsString,aPassword,@Doc);

SendQuery (@ Doc, aURL); / / відправляємо запит

if not Doc.IsEmptyDoc then / / якщо документ записаний коректно

    begin

if Doc.DocumentElement.ChildNodes.FindNode (“fault”) <> nil then / / є повідомлення про помилку

        begin

          Result:=false;

          Error:=ParseErrors(@Doc).Strings[0];

        end

      else

        Result:=true;

    end

else

  Result:=false;

end;


Якщо прийшло повідомлення про помилку, то записуємо повідомлення в змінну Error. В даному випадку структура містить тільки одне повідомлення про помилку – тому я так легко прописав:






1

Error:=ParseErrors(@Doc).Strings[0];

 


Отже, дві перевірки зроблені і ми визначили, що XML-RPC включений і працює справно, а користувач ввів коректні дані логіна і пароля і може працювати з API WordPress. Що далі? А далі починаємо основну роботу – отримуємо дані з коментарів у блозі.


2. Отримуємо дані про постах блога.


Отже, що надає в наше розпорядження WordPress. Спочатку зробимо короткий огляд методів з xmlrpc.php.


wp.getPostStatusList – Виводить значення для статусу поста. По суті на виході будемо має чотири рядки: “draft”, “pending”, “private”, “publish”.


Поки цей метод нам непотрібний.


blogger.getRecentPosts – Ця функція вже з API Blogger, але підтримується в WordPress. На виході матимемо останні пости блога, включаючи весь контент посту.


Можна використовувати метод, АЛЕ робота програми буде уповільнена так як доведеться “тягати” по Мережі пост цілком. А якщо спробуємо отримати список постів блога цілком, то, мабуть доведеться лягати спати, не дочекавшись результату. Отже – поки залишаємо метод осторонь.


metaWeblog.getRecentPosts – Аналогічно попередньому методу.


mt.getRecentPostTitles – Метод з MovableType API. Судячи з назви – те, що нам треба. Дивимося опис методу.


Метод повертає список, що містить заголовки постів блога. При цьому контент в список не записується.


Вхідні параметри:



blogid завжди дорівнює 1 (див. опис у xmlrpc.php)


numberOfPosts – Кількість постів, які необхідно вивести в список. Якщо параметр має значення більше, ніж кількість постів у блозі, то метод повертає список усіх посад.


Залишилося дізнатися, що з себе представляє цей список. А на виході ми будемо мати масив структур, що включає в себе:



Чудово. Скористаємося цим методом, а заодно навчимося аналізувати складні структури відповіді.


Про створення запиту, думаю, писати не варто. Процедура аналогічна тій, що розглянута вище. А на аналізі відповіді сервера зупинимося докладно. Стем як виглядає тип struct (структура) ми познайомилися при парсінгу відповіді, що містить помилку авторизації. Подивимося, що з себе представляє масив.


Масиви не мають назви і описуються тегом . Він містить один елемент і один або кілька дочірніх елементів , де задаються дані. Як елементи масиву можуть виступати будь-які інші типи в довільному порядку, а також інші масиви – що дозволяє описувати багатовимірні масиви. Так само можна описувати масив структур. Наприклад, масив з чотирьох елементів буде виглядати так:

<array>

  <data>

     <value><i4>34</i4></value>

Привіт, Світ!

     <value><boolean>0</boolean></value>

     <value><i4>-34</i4></value>

  </data>

</array>


У нас на виході з методу mt.getRecentPostTitles
міститиметься масив структур, Причому одна структура – це інформація по одному посту блогу. Отже, читання даних по постам блога можна умовно розділити на наступні кроки:


1. Виділяємо з XML-документа всі елементи value


2. У кожному value читаємо всі елементи member


3. кожен другий дочірній елемент у member – Дані по посту, які необхідно запам’ятати.


Почнемо відразу з обробки відповіді. Вводимо новий тип даних:






1

2

3

4

5

6

7

8

9

10

type

TBlogPost = packed record

  id: integer;

  user_id: integer;

dateCreated: string ;/ / поки будемо зберігати дату “як є”

  title: string;

end;

 

type

TBlogPosts = array of TBlogPost;


Обробляємо відповідь сервера.






1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

[…]

/ / Т.к. в масиві всього 1 тег data, то можна отримати список елементів так

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

          case j of

            0:dateCreated:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;

            1:user_id:=StrToInt((Members[j].lastChild.firstChild as IDOMNodeEx).text);

            2:id:=StrToInt((Members[j].lastChild.firstChild as IDOMNodeEx).text);

            3:title:=(Members[j].lastChild.firstChild as IDOMNodeEx).text;

          end;

      end;

end;

[…]


Відповідно, якщо отримано повідомлення про помилку, то можна скористатися розглянутої раніше функцією.


На сьогодні все. Наступного разу продовжимо роботу з API і спробуємо отримати всі коментарі з блогу.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*