Комфортная работа с XML в PHP с использованием объектов служебных данных

Научитесь пользоваться объектами служебных данных (service data objects - SDO), создавая простой блог-журнал и добавляя записи через RSS

Cтатья предназначена для разработчиков, использующих PHP, которые хотят использовать объекты SDO в PHP и при помощи этих объектов ускорять работу с файлами XML.

Мэтью Питерс, инженер-программист, IBM UK

Мэтью Питерс (Matthew Peters) из лаборатории разработчиков IBM в Херсли (Hursley), Англия. Ранее он занимал различные должности при работе над программами серий CICS® и MQSeries® , а также провел несколько лет в фирмах - партнерах IBM по научно-техническим расчетам и параллельной обработке крупных массивов данных. В последние годы работает над программой чистки памяти для IBM JVM. У него степень бакалавра по математике (Квинс Колледж, Кембридж) и степень магистра по программированию (Оксфордский университет).



Кэролайн Мейнард, инженер-программист, IBM UK Laboratories

Кэролайн Мейнард (Caroline Maynard) из лаборатории разработчиков IBM в Херсли (Hursley), Англия. Она занималась такими областями как сети, графика и голосовые службы. В последнее время руководит разработкой IBM Java ORB, которая является основой для EJB-оболочки в WebSphere Application Server. Ее интересует интегрирование продукции IBM с открытым кодом Linux и технологиями Apache, MySQL, PHP/Perl/Python (LAMP). Диплом по математике от Сассекского Университета.



Грэм Чартерс, старший инженер-программист, IBM UK Laboratories

Грэм Чартерс (Graham Charters) из лаборатории разработчиков IBM в Херсли (Hursley), Англия. Ранее он занимал различные должности при работе над программами IBM WebSphere® Application Server и над архитектурой WebSphere Business Integration и адаптерами к ней. Сейчас в сферу его интересов входят взаимосвязи между технологиями открытого кода (Linux® , Apache, MySQL, PHP/Perl/Python (LAMP)) и платформой WebSphere. Дипломы Манчестерского Университета по программированию, числовому анализу и машинному зрению.



26.03.2007

Изучая объекты SDO и интерфейс, в котором они создаются, вы получите представление о том, какие возможности дают объекты SDO для интерфейса прикладного программиста API. Далее мы рассмотрим рабочий пример использования SDO в двухчастной программе, с помощью которой мы напишем приложение PHP для создания простого веб-лога (сетевого журнала) и раздел, показывающий этот блог в виде обновления записей блога по каналам RSS. На каждом этапе мы будем использовать для обработки файлов XML объекты SDO. Мы надеемся убедить вас в том, что SDO - очень привлекательный инструмент для работы с XML-данными в PHP.

Знакомство с объектами SDO

Начнем с рассмотрения названия Объектов Служебных Данных (Service Data Object (SDO)), чтобы понять их суть.

SDO - это объекты PHP V5. В отличие от простых объектов PHP V5, SDO предназначены только для данных и не выполняют других функций. Отсюда название: объекты данных (Data Objects). Их разработали для того, чтобы сделать данные доступными для программы, независимо от родного формата и кода, так чтобы данные структурировались и обрабатывались одинаковым способом, получены ли они из родственной базы или из XML. Поэтому их назвали объектами служебных данных. Сейчас мы обнаруживаем, что они очень полезны в сервисных программах: когда необходим обмен данными, имеющими сложную структуру.

Объекты SDO являются модификацией объектов передачи данных (Data Transfer Object). Если вы зададите веб-поиск определения "Data Transfer Object", вы найдете его в книге Мартина Фаулера (Martin Fowler) Patterns of Enterprise Application Architecture (Архитектурные схемы программ для предприятия): "Объект, который передает данные между различными процессами с целью сокращения количества запросов". Объекты передачи данных позволяют интегрировать комплексы в целые объекты для экономной передачи данных.

SDO в нескольких отношениях развивают характеристики Data Transfer Object, в результате чего создается более мощный инструмент. Однако, как и Data Transfer Objects, они только несут данные и не имеют других функций.

  • Они являются не отдельными объектами данных, а собраниями взаимосвязанных объектов. Благодаря этому они сохраняют структуру несомой информации в одном файле XML.
  • Набор SDO после изменения сохраняет записи изначальных параметров, что несколько оптимизирует алгоритмы закрытия (locking).
  • SDO - объекты, которые имеют значение только тогда, когда они загружены в память или при передаче, но данные, которые постоянно остаются в памяти и не попадают никуда за ее пределы, не всегда очень полезны. Использование SDO в PHP включает два вида так называемых Служб Доступа к Данным (Data Access Services (DAS)), которые осуществляют прием данных из хранилища и превращают их в графики SDO и наоборот, возвращают данные из графиков SDO в хранилище. Один DAS предназначен для работы с родственными базами данных, а другой для работы с файлами XML.

Кстати, SDO совместима не только с PHP, также имеются интеграторы с C++ и технологиями Java™.

Структура объекта SDO

Объект SDO представляет собой объект PHP V5. Подобно другим объектам PHP V5, объект SDO обладает некоторыми общими свойствами, но в отличие от обычного PHP V5 объекты SDO являются только носителями данных и не выполняют иных функций. Для них не требуется задавать код определения класса, и для их создания не нужен конструктор.

var_dump()

Если абстрагироваться от вопросов создания таких объектов, рассмотрим случай, когда нам нужно воспользоваться функцией SDO var_dump(): мы видим, что она является частным случаем SDO_DataObjectImpl, и мы можем видеть свойства и их количественные показатели. Например, в объекте SDO с названием $author при задании var_dump видим следующее:

Листинг 1. var_dump() для объекта SDO
object(SDO_DataObjectImpl)#2 (3) {
  ["name"]=>
  string(19) "William Shakespeare"
  ["dob"]=>
  string(28) "April 1564, most likely 23rd"
  ["pob"]=>
  string(33) "Stratford-upon-Avon, Warwickshire"
}

Этот объект данных обладает 3 свойствами, которым соответствуют строки PHP: name(имя), dob (date of birth - дата рождения) и pob (place of birth - место рождения). Объекты SDO также могут иметь свойства, характерные для собственно PHP масштабных типов: string (свойства строки), integer (интегрированные), float (плавающие) или булевы (Boolean), так же как нулевая ссылка NULL или ссылка на другой объект SDO. Вид свойства задан заранее, и при передаче параметра иного типа произойдет конвертация. Например, интегрированный параметр у свойства строки превратит интегратор в свойство.

Все объекты SDO имеют тип SDO_DataObjectImpl как и PHP, и кроме этого они имеют имя типа SDO. Функция var_dump() показывает содержание объекта данных, но не имя типа, принадлежащее ему. Для его просмотра воспользуйтесь способом getTypeName(), который запускается в данном случае командой: Author.

Далее мы увидим, где для SDO было задано такое имя типа, а также как был определен набор свойств.

Команда Print

Команда в PHP print для данного объекта выдаст такую же информацию как var_dump() в несколько усеченном виде, одной строкой (мы разбили ее на 5 для легкости прочтения).

Листинг 2. Команда print() для объекта SDO
object(SDO_DataObject)#2 (3) {
  name=>"William Shakespeare"; 
  dob=>"April 1564, most likely 23rd"; 
  pob=>"Stratford-upon-Avon, Warwickshire"
}

Задание свойств и их отображение

SDO поддерживают как синтаксическую структуру объектов, так и синтаксис ассоциативной матрицы; поэтому свойства можно было задать синтаксисом объектов:

$author->name = 'William Shakespeare';
$author->dob  = 'April 1564, most likely 23rd';
$author->pob  = 'Stratford-upon-Avon, Warwickshire';

или синтаксисом ассоциативной матрицы:

$author['name'] = 'William Shakespeare';
$author['dob']  = 'April 1564, most likely 23rd';
$author['pob']  = 'Stratford-upon-Avon, Warwickshire';

Конечно, мы можем считывать параметры объекта данных, а также задавать их с помощью тех же 2 форм:

$name_of_the_author = $author->name;

or

$name_of_the_author = $author['name'];

Многозначные и однозначные свойства

Свойство может быть многозначным или однозначным. Если свойство многозначно, var_dump() покажет это указанием на SDO_DataObjectList данного объекта, то есть на список отдельных параметров. Приведем пример для случая, когда свойство works добавлено к типу Author и создано для списка строк (strings):

Листинг 3. Команда var_dump() для объекта SDO с многозначным свойством
object(SDO_DataObjectImpl)#2 (4) {
  ["name"]=>
  string(19) "William Shakespeare"
  ["dob"]=>
  string(28) "April 1564, most likely 23rd"
  ["pob"]=>
  string(33) "Stratford-upon-Avon, Warwickshire"
  ["works"]=>
  object(SDO_DataObjectList)#4 (2) {
    [0]=>
    string(17) "The Winter's Tale"
    [1]=>
    string(9) "King Lear"
  }
}

В этом случае более краткий запрос print просто даст вам сообщение о том, что имеется свойство со многими параметрами, названное works, но раскрытия этих параметров вы не увидите.

Листинг 4. Print для SDO, содержащего свойства многими численными характеристиками.
object(SDO_DataObject)#2 (4) {
  name=>"William Shakespeare"; 
  dob=>"April 1564, most likely 23rd"; 
  pob=>"Stratford-upon-Avon, Warwickshire"; 
  works[2]
}

Для просмотра содержания свойств works следует задать инструкцию print для каждого из них.

Поскольку SDO_DataObjectList содержит интерфейс PHP ArrayAccess, многопараметрические свойства проявляются подобно массивам данных PHP. Например, мы могли бы добавить в список еще 2 произведения:

$author->works[] = "The Winter's Tale";
$author->works[] = "King Lear";

Если нам захочется повторить параметры и вывести их, мы можем действовать так:

foreach ($author->works as $work) {
  print $work . "\n";
}

Предупреждение: SDO_DataObjectList не абсолютно соответствует массиву данных PHP. Например, unset для пункта в списке означает выстраивание всех последующих строк списка в случайном порядке (shuffle). Кроме того, в списке не должно быть пробелов между компонентами указателя.

Интерфейс отражения - Reflection API

Мы уже видели, как var_dump() и print выводят список свойств, заданных для объекта SDO. Для получения самого подробного списка, с отображением свойств, которые были заданы автоматически, существует Интерфейс отражения, он описан в разделе SDO пособия по PHP (см. Ресурсы).

Комбинирование объектов SDO: Сложные структуры

Объекты SDO служат организации структурированных данных, при этом отдельно взятый объект может включить только ограниченный объем. Емкость SDO возрастает, когда между ними созданы связи, позволяющие организовывать их в графики объектов.

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

Приведем простой пример: Мы снова применяем var_dump() для вывода данных объекта SDO $author, но на этот раз свойство name определено не как простая строка, а как ссылка на другой объект SDO. Этот второй объект SDO состоит из имени автора с 2 собственными свойствами: first и last. Когда мы выводим данные из второго объекта, мы видим их оба, потому что var_dump() следует ссылке от объекта author до объекта name:

Листинг 5. var_dump() дли 2 связанных объектов SDO
object(SDO_DataObjectImpl)#2 (3) {
  ["name"]=>
  object(SDO_DataObjectImpl)#3 (2) {
    ["first"]=>
    string(7) "William"
    ["last"]=>
    string(11) "Shakespeare"
  }
  ["dob"]=>
  string(28) "April 1564, most likely 23rd"
  ["pob"]=>
  string(33) "Stratford-upon-Avon, Warwickshire"
}

Не рассматривая вопросов создания этих 2 объектов SDO, мы можем сказать, что второй объект назначен свойству name объекта author, как и в строках, рассмотренных выше. Вся строка может иметь такой вид:

Листинг 6. Назначение ссылки с использованием синтаксиса объекта
$name->first  = 'William';
$name->last   = 'Shakespeare';

$author->name = $name;	// assign an SDO to the name property of $author
$author->dob  = 'April 1564, most likely 23rd';
$author->pob  = 'Stratford-upon-Avon, Warwickshire';

или так:

Листинг 7. Назначение ссылки с использованием синтаксиса ассоциативной матрицы
$name['first']  = 'William';
$name['last']   = 'Shakespeare';

$author['name'] = $name;	// assign an SDO to the name property of $author
$author['dob']  = 'April 1564, most likely 23rd';
$author['pob']  = 'Stratford-upon-Avon, Warwickshire';

Здесь $author и $name сами являются объектами SDO.

Полезно твердо определиться с использованием слова name, так как оно может быть названием типа SDO и названием свойства. Далее будет объяснено, как созданы $author и $name в качестве объектов определенного типа SDO. Если мы применим к ним команду getTypeName(), мы увидим названия типов. Предположим, что это - Author и Name. Тогда объект $author обладает свойством, называемым name. Оно задано для того, чтобы ему можно было назначать только объекты этого типа SDO Name. Если вы попытаетесь назначить SDO другого типа (например, другого автора) или простого типа, SDO выдаст отказ. Конверсии типов для ссылок SDO не существует. Но существует наследование свойств: SDO распознает иерархию наследования свойств и при наличии свойств, характерных для определенного типа, можно задать подтип.

Итак: Имеется объект $name, он относится к определенному типу SDO Name, и он назначен свойству $author под названием name.

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

Многозначные и однозначные свойства ссылок

Мы уже видели первый из этих аспектов, рассматривая свойства простых ссылок: Свойства ссылок могут быть многозначными или однозначными. Многозначное свойство указывает на объект SDO_DataObjectList, который является списком объектов данных. Эти объекты данных принадлежат к 1 типу. Предположим, что мы составляем список произведений автора в виде многозначной ссылки на объекты SDO типа Work, в котором SDO типа Work содержат название произведения и приблизительную дату его написания. Предположим также, что они сохраняют простую ссылку на SDO типа Name. В этом случае структура графика объектов SDO может выглядеть таким образом:

Рисунок 1. Объекты SDO с многозначными и однозначными свойствами ссылок
Объекты SDO с многозначными и однозначными свойствами ссылок

Включающие или исключающие свойства ссылок

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

Понятие включения и его противоположности характерно только для свойств ссылок и нуждается в объяснении. Как мы уже упоминали, одной из целей SDO является репрезентация структурированных данных, которая обычно хранится в виде XML. Хорошо сделанный документ XML обладает иерархичностью: Вверху - простой элемент, обычно называемый корневым или документным, который, как правило, включает другие элементы, и так далее. Поскольку каждый элемент включен в стартовый и конечный теги включающего его элемента, структура напоминает древо. Рассмотрим пример с теми же свойствами: author и name. Один из способов отображения этих объектов, к которым мы применяли команду var_dump, в XML.

Листинг 8. Пример документа XML с иллюстрацией включения
<author>
  <name>
    <first>William</first>
    <last>Shakespeare</last>
  </name>
  <dob>April 1564, most likely 23rd</dob>
  <pob>Stratford-upon-Avon, Warwickshire</pob>
</author>

Простые элементы <first> и <last> содержатся в элементе <name>, который, в свою очередь, находится в элементе <author>. Простые элементы <first> и <last> моделируются как примитивные или как элементы строки (string) свойства для названия объекта SDO. Наличие элемента <name> внутри элемента <author> моделируется как свойство включающей ссылки для свойства name объекта author для name данного объекта SDO.

Итак, если эти отношения включения для SDO являются включающими ссылками, что же такое не включающая ссылка? Хотя не все программы их используют, XML также позволяет задавать связи между элементами вне иерархической зависимости включения, при помощи идентификаторов XML - ID или IDREF. Именно такие дополнительные ссылки SDO моделирует в качестве не включающих ссылок.

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

Листинг 9. Пример документа XML с отношением ID/IDREF (невключающим)
<?xml version="1.0" encoding="UTF-8"?>
<company xmlns="companyNS" 
         xsi:type="CompanyType" 
         xmlns:tns="companyNS" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         name="MegaCorp" 
         employeeOfTheMonth="E0003">
  <departments name="Advanced Technologies" location="NY" number="123">
    <employees name="John Jones" SN="E0001"/>
    <employees name="Jane Doe" SN="E0003"/>
    <employees name="Al Smith" SN="E0004" manager="true"/>
  </departments>
</company>

Вы видите, как XML моделирует простую иерархию включения там, где в одиночном элементе company содержится элемент departments, который в свою очередь содержит три элемента employees (сотрудники). Возможно, лучше было использовать единственное число эля элементов "Отделы" и "Сотрудники". Когда этот документ загружается в память в качестве графика объектов SDO, график будет содержать 5 объектов данных и 2 списка объектов данных. Появится один объект данных company, один объект данных department и 3 объекта данных employee. Будет также 2 объекта списков - один для всех отделов (departments) (даже если отдел единственный, свойство - многозначно) и один для всех сотрудников. Объект company будет иметь свойство departments, которое будет указывать на список объектов department (в данном случае всего один отдел). У department будет свойство employees, которое указывает на список объектов employee.

У каждого объекта данных имеется одно или более простых свойств; так, company имеет свойство name, задаваемое атрибутами name и параметром 'MegaCorp', объекты данных department и employee также обладают свойствами name и т. д.

Обратите внимание на атрибут employeeOfTheMonth (работник текущего месяца) в элементе company. Вы увидите, что он содержит серийные номера (serial number) сотрудников. Хотя мы не продемонстрировали вам схему XML для данного документа XML, которая осуществляет связь атрибута серийный номер и атрибута employeeOfTheMonth, она осуществляется через XML ID и IDREF. SN (серийный номер) задается при помощи поля ID, а employeeOfTheMonth при помощи IDREF. Так задается связь между этими 2 элементами, независимо от основной иерархии.

Мы моделируем эти атрибуты ID и IDREF в объектах SDO при помощи не включащих ссылок. Подобно ссылкам ID и IDREF в XML, не включающие ссылки похожи на дополнительный слой в иерархии включения. В правила SDO входит следующее: как IDREF не может ссылаться на элемент XML, если этого элемента нет в документе, так и любой объект SDO в графике, доступный не включающей ссылке, должен быть доступен и включающей корневой ссылке. Нельзя указывать на объект SDO одной только не включающей ссылкой. Эта характеристика графиков SDO, названная closure (замыкание), проверяется при каждой записи объектов SDO в память любыми службами доступа к данным (DAS).

Покажем диаграмму, иллюстрирующую эти положения. Обратите внимание на то, что не включающая ссылка не зависит от иерархии включения, а также на то, что сведения employee, доступные данной не включающей ссылке, доступны также следующим включающим ссылкам корневого элемента.

Рисунок 2. Объекты SDO, иллюстрирующие свойства включающих и не включающих ссылок
Объекты SDO, иллюстрирующие свойства включающих и не включающих ссылок

Как и включающие ссылки, не включающие могут быть однозначными или многозначными.

Их используют приблизительно так же, как ID и IDREF в XML, то есть в некоторых программах очень часто, а в других их вовсе не используют.


Создание объектов данных

Теперь мы знаем, как выводить и задавать свойства объекта данных и как осуществлять связи между объектами. Пора объяснить, как создаются объекты данных.

Объекты SDO создают при помощи объектов фабрики данных (data factory object). До создания из них чего бы-то ни было необходимо определить для объекта модель, то есть набор имен типов свойства, которые может иметь каждый объект. Именно эта модель ограничивает свойства, которыми может обладать объект, так что, например, скорее всего, для объекта данных не получится задать свойство, которое отсутствовало в модели, а также невозможно будет назначить объект данных такому свойству, которое предназначено для свойств иного типа.

При разработке объектов SDO в PHP доступны 3 способа инициализации фабрики данных для создания объектов. Первые два требуют привлечения DAS, то есть предполагается, что вы считываете данные из реляционной базы данных или файла XML и записываете данные на те же носители. В этом случае DAS создаст и инициализирует фабрику данных, но она будет храниться в скрытом виде и предложит вам интерфейс для создания объектов данных. Еще один способ получения фабрики данных - создать ее самому и использовать команды AddType() и AddPropertyToType() для задания модели, так же, как это делают DAS. Хотя это не часто используют, мы кратко покажем и этот способ, тогда вам станет понятнее, что же происходит за кулисами включенных DAS.

Вот как задают те 2 типа, которые мы уже использовали в наших примерах:

$data_factory = SDO_DAS_DataFactory::getDataFactory();
$data_factory->addType('NAMESPACE', 'Author');
$data_factory->addType('NAMESPACE', 'Name');

Возможно, вы помните, как мы показывали вызов объекта командой getTypeName()$author и выводили данные Author. Именно такой вызов addType() задаст это название в модели объекта SDO.

Все типы существуют в области имени. В данном случае область имени назначена NAMESPACE, но ее можно было также оставить незаполненной или обнулить, если бы область имени не требовалась.

Покажем способ задания простого свойства строки first для типа Name:

Листинг 10. Добавление простого свойства в тип SDO
$data_factory->addPropertyToType (
  'NAMESPACE' , 'Name',              	// adding to NAMESPACE:Name ...
  'first',                           	// ... a property called first ...
  SDO_TYPE_NAMESPACE_URI, 'String',  	// ... to take string values ...
  array('many' => false));           	// ... which is single-valued.

Два первых задания этого довольно несуразного запроса указывают область имени и имя типа, к которым мы добавляем свойство - в данном случае NAMESPACE:Name. Третье задание - название свойства, которое мы добавляем - в данном случае first. Четвертое и пятое задания - область имени и имя типа, которые может принимать данное свойство - в данном случае commonj.sdo:String (постоянная величина SDO_TYPE_NAMESPACE_URI является commonj.sdo:; это - область имения, в котором простые типы функционируют в этой модели SDO). Последнее задание - ассоциативная матрица, которая указывает свойства, например, однозначность или многозначность, а также ссылки на другие объекты, как включающие, так и не включающие.

После перечисленных запросов можно вызвать данную фабрику данных для создания нового объекта данных определенного типа Name, который будет обладать свойством first, то есть будет готов к получению объектов со строками, определенными для данного типа. Чуть ниже мы приведем пример.

Вот как назначается эта включающая ссылка при помощи Author для Name:

Листинг 11. Добавление включающей ссылки к типу объектов SDO
$data_factory->addPropertyToType (
  'NAMESPACE' , 'Author',           	// adding to NAMESPACE:Author ...
  'name',                           	// ... a property called name ...
  'NAMESPACE', 'Name',              	// to take objects of type NAMESPACE:Name ...
  array('many' => false, 'containment' => true));	// ... single-valued \
  and containment.

Далее мы добавляем свойство name к типу Author и ограничиваем его объектами типа Name. Свойство name определяет однозначную включающую ссылку.

Еще раз подчеркнем, что редко приходится самому определять, таким образом, тип и свойства фабрики данных. Обычно за вас это делают DASы, и об этом мы поговорим в следующем разделе.

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

Когда модель для фабрики данных уже указана, мы можем приступить к созданию объектов данных. Первый создаваемый объект может быть создан только запросом к фабрике данных или при помощи метода, подходящего для нашего DAS. Ниже мы пользуемся фабрикой данных для объекта верхнего уровня и передаем ему имя типа и область данных:

$author = $data_factory->create('NAMESPACE', 'Author');

Когда мы уже получили один объект, мы можем выбрать один из двух способов создания производных объектов данных. Прямой способ - вновь воспользоваться соответствующим типом из фабрики данных и назначить новый объект соответствующему свойству в порождающем объекте.

Листинг 12. Создание и обработка второго объекта данных при помощи запроса фабрики данных
$name = $data_factory->create('NAMESPACE', 'Name');
$author->name = $name;

Существует и более распространенный и экономный способ. Вызовите createDataObject() для существующего объекта, передавая ему название свойства, которое будет включать этот новый объект.

$name = $author->createDataObject('name');

Этот запрос генерирует поиск в модели: на какой вид объекта данных может указывать данное свойство? Потом создается объект данных такого типа и назначается свойству name, потом возвращается вновь созданный объект данных. Мы используем один объект данных в качестве фабрики данных для объектов, на которые ссылается первый объект. Когда у вас появился исходный объект, так обычно создают новые.

Службы доступа к данным - Data Access Services

Теперь давайте рассмотрим, как то, что мы сейчас делали, можно осуществить более распространенным способом, с применением DAS. Начнем с припоминания известного.

Функция SDO DAS - загружать данные из памяти и преобразовывать их в графики данных для прикладной программы, которой мы пользуемся, а потом вновь разворачивать график данных. Для создания SDO в PHP существуют два вида DAS: один для работы с данными в XML и другой для работы с реляционной базой данных. Каждая из них описана в документации PHP, поэтому мы только кратко опишем их. Во второй половине нашей статьи вы также можете найти несколько примеров использования XML DAS.

Оба вида DAS запускаются при включении модели объекта SDO, при запросах addType() и addPropertyToType(), которые вы уже рассматривали. Модель нужна для координации типов, свойств и связей, существующих в исходном XML или в реляционной базе данных, и эту информацию необходимо указать для DAS. Способы сообщения этой информации для разных DASов - разные.

XML DAS всегда запускает свою модель чтением и анализом файла - описания схемы XML (в виде файла XSD), соответствующий документу XML, который загружается. Правила составления карты по схеме XML даны в документации к SDO V2.0, но суть их можно выразить следующим образом: любой элемент сложного типа в модели становится типом объекта SDO. Включающие связи между элементами отражаются во включающих ссылках между файлами. Простые типы (например, строки - strings) станут простыми свойствами объектов SDO. Атрибуты тоже станут свойствами.

Файл описания схемы после инициализации обычно передается в XML DAS статичным методом create() для этого класса, например:

$xmldas = SDO_DAS_XML::create('author.xsd');

Когда модель для XML DAS уже задана, можно использовать способы loadFile() и saveFile() для загрузки и сохранения данных XML в файл, а также loadString() и saveString() для загрузки и сохранения его в строке. Есть еще способ createDocument() для создания новых документов без использования загружаемого файла.

Совершенно иначе инициализируют Relational DAS. Он будет использовать данные, выдаваемые прикладной программой и при создании передаваем в DAS в виде ассоциативных матриц. Одной из характеристик является наличие коллекции ассоциативных матриц, которые описывают базу данных: названия таблиц, колонок, первичные и внешние ключи. Эту информацию в принципе можно получать из базы данных автоматически. Хотя сейчас это не используется, возможно, такой метод будет реализован в будущих версиях Relational DAS. Еще важно, чтобы программа определяла способ отображения данных в базе в виде графиков данных, определяя содержание верхнего раздела в графике данных и что будет отображаться в верхнем разделе, какие внешние ключи будут считаться включающими свойствами и т.п.

Когда Relational DAS уже воспринял модель, ее можно использовать для загрузки данных в память в виде объектов SDO. Следует поставить перед Relational DAS задачу: сделать запрос на языке SQL, тогда результаты запроса будут сохранены в виде графика объектов SDO. Если далее будете обновлять эти объекты, делать добавления или сокращения в графике, задавайте команду "применить изменения" (applyChanges) в программе Relational DAS и будет сгенерирован сообщение о результатах поиска SQL с целью внесения изменений в базу данных. В онлайновой документации и в других статьях на сайте developerWorks можно найти много другой информации по Relational DAS. (см. Ресурсы).

Черновой пример обновления по каналу RSS (Really Simple Syndication)

Для иллюстрации использования SDO и XML DAS мы создадим приложение, в котором для работы с XML используются только SDO. У нашего приложения 2 раздела: простая программа для создания блогов, которая сохраняет содержание блога в виде файла XML и программа, которая считывает файл XML и осуществляет его редактирование в форме обновления по каналу (RSS). Сейчас вы увидите, что использование SDO чрезвычайно облегчает работу в PHP с файлами XML. См. код здесь: Download.

Блог-приложение

По структуре наш блог и блог-приложение очень просты. Первый скрипт выводит пустой файл HTML, в который пользователь помещает новостное сообщение с заголовком и описанием. Вот экран с нашей первой записью:

Рисунок 3. Добавление записи в блог-журнал
Добавление записи в блог-журнал

Когда мы передаем эту записи, второй скрипт, который является адресом для бланка первого скрипта, записывает данные в блог-журнал и вывешивает экран для подтверждения добавленной записи.

Рисунок 4. Подтверждение
Подтверждение

Мы еще рассмотрим эти скрипты, но сначала взгляните на наш блог-журнал с одной записью:

Листинг 13. Журнал с одной записью
<?xml version="1.0" encoding="UTF-8"?>
<blog xsi:type="blog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <item>
    <title>Hello World</title>
    <description>The traditional opening in all fields of computing</description>
    <date>Thu, 6 Apr 2006 15:25:58 BST</date>
    <guid>b787c22d15b34b0eb29305e9ea17d8e9</guid>
    <from_ip>127.0.0.1</from_ip>
  </item>
</blog>

Здесь один элемент верхнего уровня, <blog>, и он содержит несколько <item>. У каждого элемента имеется название, основной текст, дата и поле индивидуального ключа guid (для идентификации пользователя в мировом масштабе), который выдается при создании записи. Хотя для самого журнала ключ не нужен, он потребуется позже при RSS-обновлении. Здесь мы задаем guid, переставляя местами цифры в дате и времени, когда добавляли запись. Чтобы как-то обозначить автора записи, мы также указываем IP адрес сайта автора.

Поскольку блоги кумулятивны и мы создаем блог по образцу, показанному ранее, с возможностью добавления и удаления записей, воспользуемся SDO XML DAS. Вы помните, что XML DAS получает информацию о модели, которой должны придерживаться объекты SDO из файла схемы XML. Значит, такую схему следует составить.

Листинг 14. Схема XML для блог-журнала
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="blog">
     <xs:complexType>
       <xs:sequence>
         <xs:element name="item" maxOccurs="unbounded">
           <xs:complexType>
             <xs:sequence>
               <xs:element name="title" type="xs:string"/>
               <xs:element name="description" type="xs:string"/>
               <xs:element name="date" type="xs:string"/>
               <xs:element name="guid" type="xs:string"/>
               <xs:element name="from_ip" type="xs:string"/>
             </xs:sequence>
           </xs:complexType>
         </xs:element>
       </xs:sequence>
     </xs:complexType>
   </xs:element>
 </xs:schema>

Вы видите, что этот файл схемы полностью соответствует примеру документа, приведенному выше. В нашем журнале есть элемент документа с названием <blog>, и в нем содержится неограниченное число записей с названием, описанием и т.п.

Код приложения

Покажем скрипт HTML, который выводит запрос о применении заголовка и описания (для этого PHP и SDO не требуются):

Листинг 15. Страница HTML: включение записи в блог-журнал
<html>
<head>
<title>Add an item to my half-baked blog</title>
</head>

<body>
<p>
<strong>Add an item to my half-baked blog</strong>
<br/>
<br/>

<form method="post" action="additem.php">
  Title:
  <br/>
  <input type="text" size="50" name="title"/>
  <br/>
  Description:
  <br/>
  <textarea rows="5" cols="50" name="description"></textarea>
  <br/>
  <input value="Submit" type="submit"/>
</form>
</p>
</body>
</html>

Это осуществляет ссылку на второй скрипт, additem.php:

Листинг 16. Скрипт PHP: добавление записи в блог-журнал
<html>

<head>
<title>An item has been added to my half-baked blog</title>
</head>

<body>

<p><strong>An item has been added to my half-baked blog</strong><br />

<?php
/* initialize the XML DAS and read in the blog */
$xmldas                = SDO_DAS_XML::create('./blog.xsd');

/* read in and parse the XML instance document */
$xmldoc                = $xmldas->loadFile('./blog.xml');
$blog                  = $xmldoc->getRootDataObject();

/* create a new item and copy info from the html form */
$new_item              = $blog->createDataObject('item');
$new_item->title       = $_POST['title'];
$new_item->description = $_POST['description'];
$new_item->date        = date("D\, j M Y G:i:s T");
$new_item->guid        = md5($new_item->date);
$new_item->from_ip     = $_SERVER['REMOTE_ADDR'];
 
/* write the blog back to the file from whence it came */
$xmldas->saveFile($xmldoc,'./blog.xml',2);

echo "Title: "         . $new_item->title;
echo "<br/>";
echo "Description: "   . $new_item->description;
echo "<br/>";
echo "Date: "          . $new_item->date;
?>

</p>
</body>
</html>

Этот второй скрипт был нашим первым случаем использования SDO и XML DAS, поэтому стоит его проанализировать, хотя нового мы почти не обнаружим.

Вначале мы используем статичный метод SDO_DAS_XML::create() для инициализации XML DAS с файлом схемы, содержащей описание нашего блога. Этот XML DAS проанализирует синтаксис файла схемы и определит вид модели типов и свойств для SDO, а также обратится к addType() и addPropertyToType() в фабрике данных, чтобы запустить ее вместе с этой моделью SDO.

Следующий запрос loadFile() считывает и анализирует документ XML и создает объект, представляющий этот документ. Представим себе, что мы добавляем вторую запись, а запись, которую мы добавили ранее, с заголовком Hello World уже сохранена. Невидимо для нас, loadFile() сделал несколько запросов к createDataObject() для создания объектов SDO. Поскольку мы приняли условие о том, что загружаем блог с одной записью, XML DAS создал один объект SDO типа blog и один объект типа item. Объект данных blog будет содержать многозначное свойство включающей ссылки с названием item, это ссылка на список с одним компонентом. Когда мы задаем getRootDataObject() для объектов этого документа, мы получаем SDO, представляющий элемент документа <blog>. Если мы применим к нему var_dump(), мы увидим:

Листинг 17. Экран блог-журнала после запроса var_dump()
object(SDO_DataObjectImpl)#9 (1) {
  ["item"]=>
  object(SDO_DataObjectList)#10 (1) {
    [0]=>
    object(SDO_DataObjectImpl)#11 (5) {
      ["title"]=>
      string(11) "Hello World"
      ["description"]=>
      string(50) "The traditional opening in all fields of computing"
      ["date"]=>
      string(28) "Thu, 6 Apr 2006 15:25:58 BST"
      ["guid"]=>
      string(32) "b787c22d15b34b0eb29305e9ea17d8e9"
      ["from_ip"]=>
      string(9) "127.0.0.1"
    }
  }
}

Вы наблюдали соответствия между документом, схемой и графиком данных SDO.

Далее мы создаем новую запись и копируем заголовок записи и ее описание, введенное в файл HTML. В этот момент мы также берем текущую дату и время, генерируем guid и сохраняем IP адрес сайта, с которого послана запись. Обратите внимание: приложение создает новую запись запросом createDataObject() к объекту SDO этого журнала, который передает записи свойство name. Как мы уже говорили, невидимо для нас модель подвергается проверке, и обнаружено, что свойству item назначены SDO типа item (первое - название свойства, второе - название типа), потом создается объект данных типа item и ему назначается свойство многозначной включающей ссылки item в SDO $blog.

Наконец, мы вызываем saveFile() и вписываем блог-журнал в файл XML, где он и был вначале.

А если бы мы решили добавить вторую запись с заголовком "What next? (А дальше?)" Тогда журнал мог бы выглядеть так:

Листинг 18. Блог-журнал с новой записью
<?xml version="1.0" encoding="UTF-8"?>
<blog xsi:type="blog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <item>
    <title>Hello World</title>
    <description>The traditional opening in all fields of computing</description>
    <date>Thu, 6 Apr 2006 15:25:58 BST</date>
    <guid>b787c22d15b34b0eb29305e9ea17d8e9</guid>
    <from_ip>127.0.0.1</from_ip>
  </item>
  <item>
    <title>What next?</title>
    <description>At this point we need a witty remark</description>
    <date>Thu, 6 Apr 2006 15:46:27 BST</date>
    <guid>582befcb0ab4ac24c5b7966529097b5a</guid>
    <from_ip>127.0.0.1</from_ip>
  </item>
</blog>

Знакомство с RSS (Really Simple Syndication

RSS

В статье по форматам RSS нельзя обойти вниманием их существующие версии. Существует 2 отличных друг от друга направления в разработке RSS. Названия версий способны сбить с толку, потому что, например, версии 0.92 и 2.0 родственны, а 1.0 из другого лагеря. В Сети много файлов, созданных при помощи версии 2.0, поэтому ей мы и воспользуемся. Если вам хочется узнать больше об истории RSS, мы рекомендуем обратиться к книге издательства O'Reilly Developing Feeds with RSS and Atom (Создание обновлений при помощи RSS и Atom), автор Ben Hammersley, первый раздел которой представляет подробную историю (см. Ресурсы).

Мы будем по возможности лаконичны. Это поможет понять структуру документа XML, который мы создаем, особенно если вы никогда не видели, как выглядит обновление по каналу RSS.

Обновление RSS - это просто документ XML, задачей которого является сохранение в памяти краткого содержания части сайта или всего сайта. Обновление RSS обычно содержит список статей, размещенных на сайте в последнее время, для каждой из них - заголовок, краткое содержание и ссылку на полный текст. В нашем примере мы будем ориентироваться на парадигму новостных блогов и создавать обновление RSS из нашего блога. Но когда вы увидите код, который генерирует обновление, вы поймете, что на самом деле очень просто создавать такие краткие содержания из любого материала, структура которого проста и определяется как список.

Очень редко файлы XML читают в оригинальном формате. Вместо этого для чтения и редактирования используют простую программу, так называемый - считыватель обновлений (feed reader). Существуют десятки таких программ. Мы протестировали наше приложение с небольшим, но разнообразным набором таких программ для Windows® . Выявились некоторые особенности в интерпретации обновлений, поэтому мы отобрали небольшую подгруппу, с которой считыватели обновлений нормально работают. Все считыватели, которыми мы пользовались, - бесплатные программы. В нашу подгруппу попали Awasu Personal Edition, SharpReader, Mozilla Thunderbird и Live Bookmarks (в составе Mozilla Firefox). Из этого списка Awasu оказалась наиболее полезной, поскольку она делает повторное считывание по требованию и показывает обновление точно в том виде, в котором оно была получена.

Файл схемы для RSS

Для работы с документом XML и XML DAS следует запустить файл схемы XML, который использует DAS для создания модели объекта SDO. Для версии RSS V2.0 нет официального файла схемы, хотя характеристики и образцы обновлений можно найти на сайте Юридического факультета Гарвардского университета Ресурсы). Сетевой поиск RSS20.xsd поможет вам найти этот файл схемы для RSS V2.0. Однако файл, который мы нашли, оказался слишком длинным и в нем содержалось слишком много ненужных нам элементов, поэтому мы его серьезно упростили и получили файл схемы, который нам был нужен:

Листинг 19. Упрощенная схема для подгруппы RSS V2.0
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="rss">
    <xs:complexType>
      <xs:attribute name="version" default="2.0" />
      <xs:sequence>
        <xs:element name="channel" type="channel" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="channel">
    <xs:sequence>
      <xs:element name="title" type="xs:string"/>
      <xs:element name="link" type="xs:string"/>
      <xs:element name="description" type="xs:string"/>
      <xs:element name="copyright" type="xs:string"/>
      <xs:element name="language" type="xs:string"/>
      <xs:element name="webMaster" type="xs:string"/>
      <xs:element name="lastBuildDate" type="xs:string"/>
      <xs:element name="pubDate" type="xs:string"/>
      <xs:element name="item" type="item" minOccurs="0" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="item">
    <xs:sequence>
      <xs:element name="title" type="xs:string"/>
      <xs:element name="link" type="xs:string"/>
      <xs:element name="description" type="xs:string"/>
      <xs:element name="guid" type="guid"/>
      <xs:element name="pubDate" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
  
  <xs:complexType name="guid">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="isPermaLink" use="optional" type="xs:boolean"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

</xs:schema>

Если у вас еще нет опыта разбора схем XML, понять ее нелегко. Вот что она сообщает:

  • Обновление состоит из единичного элемента RSS.
  • Этот элемент RSS состоит из нескольких элементов каналов.
  • Каждый элемент канал состоит из нескольких элементов новость.
  • Данный элемент RSS имеет единственный атрибут: версия.
  • Каждый элемент канал содержит несколько других элементов, например, информацию об авторском праве (одно упоминание) и список новостей.
  • Каждая новость содержит элемент заголовок, описание, ссылку с URL соответствующей статьи, дату публикации и guid.

Значение кода guid описано в документации к RSS. Строка используется только для данной статьи. Эта строка может быть непрозрачным идентификатором (opaque identifier) или URL адресом статьи, тогда атрибут isPermaLink следует задать как true и считыватель обновлений воспримет его как ссылку. Мы предпочли выбрать непрозрачный идентификатор и использовали элемент <link> для обратного указания на статью.

Создание обновления

Позже мы опишем приложение, которое создает RSS-обновление из блога. А вначале рассмотрим, как будет выглядеть обновление, если блог, для которого оно предназначено, состоит пока только из указанных выше двух записей. Если удастся, вы поймете, как эта структура соотносится со схемой XML, которую мы создали для нашего RSS-обновления.

Листинг 20. Блог в виде выдачи как RSS-обновление
<?xml version="1.0" encoding="UTF-8"?>
<rss xsi:type="rss" \
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
  <channel>
    <title>My half-baked feed - RSS/PHP edition</title>
    <link>http://localhost/rss/index.php</link>
    <description>Comment from Yours Truly</description>
    <copyright>All mine!</copyright>
    <language>en-gb</language>
    <webMaster>mfp</webMaster>
    <lastBuildDate>Thu, 6 Apr 2006 15:47:20 BST</lastBuildDate>
    <pubDate>Thu, 6 Apr 2006 15:47:20 BST</pubDate>
    <item>
      <title>Hello World</title>
      <link>http://localhost/rss/showitem.\
      php?id=b787c22d15b34b0eb29305e9ea17d8e9</link>
      <description>The traditional opening in all fields \
      of computing</description>
      <guid isPermaLink="false">b787c22d15b34b0eb29305e9ea17d8e9</guid>
      <pubDate>Thu, 6 Apr 2006 15:25:58 BST</pubDate>
    </item>
    <item>
      <title>What next?</title>
      <link>http://localhost/rss/showitem.\
      php?id=582befcb0ab4ac24c5b7966529097b5a</link>
      <description>At this point we need a witty remark</description>
      <guid isPermaLink="false">582befcb0ab4ac24c5b7966529097b5a</guid>
      <pubDate>Thu, 6 Apr 2006 15:46:27 BST</pubDate>
    </item>
  </channel>
</rss>

А вот как будет выглядеть это обновление в представлении считывающей программы Awasu Personal Edition:

Рисунок 5. Обновление в представлении Awasu
Обновление в представлении Awasu

Если вы щелкнете по заголовкам Hello World или What next? (а рядом с ними есть маленькие иконки документов), Awasu перейдет на указанный URL адрес в элементе <link> данной записи, как будет показано ниже.

Создание обновления

Сейчас рассмотрим скрипт PHP, который генерирует это обновление:

Листинг 21. Скрипт PHP, генерирующий обновление из блога
<?php
/* Write out the header to indicate XML follows */
header('Content-type: application/xml');

/* Construct an XML DAS using the schema for RSS */
$rss_xmldas             = SDO_DAS_XML::create('./rss.xsd');

/* Load an XML file that contains a few settings */
$rss_document           = $rss_xmldas->loadFile('./base.xml');
$rss_data_object        = $rss_document->getRootDataObject();

/* Set build and publish date on the channel */
$channel                = $rss_data_object->channel;
$channel->lastBuildDate = date("D\, j M Y G:i:s T");
$channel->pubDate       = date("D\, j M Y G:i:s T");

/* Open and load the blog, using a second XML DAS */             
$blog_xmldas            = SDO_DAS_XML::create('./blog.xsd');
$blog_document          = $blog_xmldas->loadFile('./blog.xml');
$blog_data_object       = $blog_document->getRootDataObject();

/* iterate through the items in the blog and for each one
 * create a corresponding item in the rss feed 
 */
foreach ($blog_data_object->item as $item) { 
    $new_channel_item              = $channel->createDataObject('item');

    $new_channel_item->title       = $item->title;
    $new_channel_item->description = $item->description;
    $new_channel_item->pubDate     = $item->date;
    $new_channel_item->link        = \
    "http://localhost/rss/showitem.php?id=" . $item->guid;

    $guid                          = $new_channel_item->createDataObject('guid');
    $guid->value                   = md5($new_channel_item->pubDate);
    $guid->isPermaLink             = false;
}

print $rss_xmldas->saveString($rss_document,2);
?>

Нашей целью здесь является конструирование объекта данных для RSS-обновления, сообщение ее нашему блогу и создание соответствующей информации о записи в обновлении для каждой новостной записи в блог-журнале. Мы могли бы ограничиться несколькими недавними статьями и отсекать список новостей, которые старее определенной даты, но в данном случае мы производим полное копирование.

Вначале мы записываем колонтитул HTTP, чтобы показать, что далее идет документ XML. Затем мы создаем XML DAS с помощью нашей схемы RSS и загружаем файл XML, чтобы запустить этот DAS. Этот файл XML содержит несколько установок, которые практически с эволюцией новых типов обновлений – авторское право, заголовок обновления и т.п. Здесь очень удобно хранить такую информацию. Мы могли бы их также подвергнуть жесткой кодировке в скрипт в виде параметров, назначенных свойствам объектов данных в канале.

После такой инициализации свойств RSS-обновления мы получим объект данных RSS и додадим еще несколько свойств – связанных со временем создания. Более подробную информацию вы найдете в документации к RSS V2.0.

Следующие 3 сообщения открывают и загружают блог, а также принимают записи журнала из документа. Для этой операции мы используем еще один XML DAS, и это совершенно правильно, поскольку теперь у нас имеется 2 DASа разных моделей. Если нет необходимости, чтобы один DAS понимал объекты данных, созданные другим, проблем не возникнет. Иногда бывает возможно загружать оба файла схемы в один DAS, потому что он может управлять множественными файлами схем, но тогда придется разносить по разным областям имени те имена типов, которые для них являются общими – заголовок, описание, сообщение, guid. Мы предпочли распределить все это по разным DASам, поскольку мы не хотели объяснять методы работы с областью имени.

Теперь у нас загружены в память оба графика данных. Завершение обновления по каналу RSS заключается в повторах для каждой записи и создании для каждой из них соответствующей записи в обновлении. Обратите внимание на то, что сами записи копировать нельзя, не только потому что структура каждой записи в чем-то непохожа на структуру другой, но и из-за опасности копировать запись, созданную одним DASом, в график. Созданный другим – это не допускается.

Когда вся информация в обновлении приобретет желаемый вид, приложение записывает весь документ XML в виде строки с кодом saveString(). Для аккуратного форматирования и удобства чтения мы используем код saveString() и получаем отступ на 2 колонки на каждом уровне.

Вот основной файл XML:

Листинг 22. Базовый файл, содержащий несколько жестко запрограммированных параметров для обновления
<?xml version="1.0" encoding="iso-8859-1"?>
<rss 
  xsi:type="rss" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  version="2.0">
  <channel>
    <title>My half-baked feed - RSS/PHP edition</title>
    <link>http://localhost/rss/index.php</link>
    <description>Comment from Yours Truly</description>
    <copyright>All mine!</copyright>
    <language>en-gb</language>
    <webMaster>mfp</webMaster>
  </channel>
</rss>

Скрипт для вывода отдельной записи

Наконец, последняя сложность – элемент <link> в обновлении. Элемент <link> для каждой записи отсылает на адрес URL http://localhost/rss/showitem.php?... Любая программа-считыватель интерпретирует элемент <link> как команду перейти к тексту статьи. В нашем случае мы просто переходим на простую страничку, где отображенная наша запись. Обратите внимание: guid находится в конце параметра <link>, чтобы элемент showitem.php понимал, что следует отобразить. Скрипт открывает блог, извлекает запись с соответствующим кодом guid, и форматирует ее. Приводим этот код:

Листинг 23. Скрипт PHP для вывода отдельной записи
<html>

<head>
<title>Show Item</title>
</head>

<body>
<p><strong>My half-baked feed</strong><br />

<?php
/* open and load the blog */
$xmldas    = SDO_DAS_XML::create('./blog.xsd');
$xmldoc    = $xmldas->loadFile('./blog.xml');
$blog      = $xmldoc->getRootDataObject();

/* get the id of the desired item from the URL */
$id        = $_GET['id'];   // id was inserted in the URL by the feed

/* use XPath to find the right item within the blog */
$item      = $blog["item[guid=$id]"]; 

echo "<br/>";
echo "The following item was added on " . $item->date;
echo " from ip address: " . $item->from_ip;
echo "<br/>";
echo "<br/>";
echo "Title: " . $item->title;
echo "<br/>";
echo "Description: " . $item->description;
echo "<br/>";
   
?>
</p>
</body>
</html>

Этот скрипт создает DAS при помощи XSD, загружает документ и получает корневой объект данных, вы уже знакомы с таким процессом. Теперь остается единственный незнакомый вам метод работы с SDO: использование выражения типа XPath для поиска записи в графике данных. Весь блог при этом буден загружен в память в качестве графика данных, а выражение ["item[guid=$id]"] (не забудьте: код $id уже заменен на реальную величину $id by PHP) будет воспринято программой как поисковая строка XPath. Коду $item будет назначена конкретная запись с ее идентификатором (ID). SDO содержит мощную группу XPath.

Вот как это будет выглядеть, если мы перейдем по ссылке с первой записи (представлено в Awasu):

Рисунок 6. Первая новость отображается в Awasu
Первая новость отображается в Awasu

Как начать работу

Возможно, вам сейчас интересно читать нашу статью, но когда вы скачаете код и запустите его на своем компьютере и начнете экспериментировать, вам могут помочь такие советы.

Во-первых, в скрипте PHP, который генерирует обновление, ссылка дается как полный адрес URL. Скрипт рассчитан на полную установку поддиректории “rss” в корне для файлов документов на вашем веб-сервере – например, для Apache это будет htdocs/rss.

Разные считыватели обновлений не всегда следуют одинаковой логике в интерпретации кода guid и ссылки, особенно если ссылка неполная или если коду isPermaLink назначен параметр “true” или не задан вообще. В некоторых случаях в программе SharpReader, принимается код guid и для создания ссылки программа помещает его в конце адреса сайта, с которого поступило обновление. Программа Awasu просто помещает код http:// в начало кода guid. Наша окончательная схема (см. выше) ссылки и код guid с неверным кодом isPermaLink нормально работала со всеми нашими программами считывания.

Некоторые считывающие программы действуют по принципу почтового клиента, и если они хоть однажды встретили в записи код guid, эта запись будет постоянно выводится на экран обновления, даже если в последней версии этот элемент отсутствует. Похожая путаница возникает, если 2 записи заканчиваются одинаковым кодом guid, или для записи меняется код guid. Лучше этого не делать, но при экспериментировании такое случается и впоследствии бывает трудно от этого избавиться.

Обычно бывает достаточно удалить обновление из считывающей программы, но в программе Thunderbird единственный способ полностью очистить обновление - удаление соответствующих директориев в RSS News & Blogs учетной записи в почтовом клиенте Thunderbird's mail.
Примечание: Производите удаление так, чтобы не уничтожить другую важную информацию, например, директории для электронных писем.

Вы всегда можете удостовериться, что ваше RSS-обновление обслуживается, проверив лог веб-сервера. Если вы работаете в системе UNIX® или в Windows, снабженном инструментарием MKS или cygwin, вы можете также использовать для него код tail -f.

Заключение

Мы стремились познакомить вас с Объектами Служебных Данных (SDO), с интерфейсом API, который позволяет работать с ними и привели примеры того, насколько удобны SDO при работе с данными XML, полученными из PHP, как логично эти объекты выражают структурированные данные документа XML. Мы уверены, что показанная нами программа для блог-журнала не самая совершенная и существуют более прогрессивные способы обновления, мы надеемся, что это приложение вас заинтересовало.

Вы теперь знает, что для работы с XML при помощи SDO потребуется файл схемы XML, из которого XML DAS может инициализировать модель типов и свойств и, возможно, это вас обеспокоило. Если у вас есть такая схема, тогда интерфейс API SDO поддерживает порядок во всех назначенных заданиях и в графике данных, обеспечивая, чтобы все изменения объектов и графика были в рамках схемы – таким образом, происходит как бы постоянная рабочая проверка схемы. Возможно, это будет для вас полезным.

Мы исходили из того, что одна из изначальных целей SDO – дать методы работы со структурированными данными, независимо от источника этих данных. Мы не показали использования Relational DAS, но хотелось бы, чтобы вы поняли: если бы мы захотели это сделать, мы могли бы написать приложение для обработки данных в реляционной базе, а не в XML. И в этом случае нам бы потребовалось инициализировать Relational DAS, а не XML DAS, и в этом было бы отличие, но все остальные операции с объектами SDO были бы аналогичными.

Желаем вам успехов в использовании объектов SDO для работы со структурированными данными в PHP.


Загрузка

ОписаниеИмяРазмер
PHP scripts, XML, and XSD filesos-php-sdo-download.zip4KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=204370
ArticleTitle=Комфортная работа с XML в PHP с использованием объектов служебных данных
publish-date=03262007