Обмен данными между приложениями с помощью XML+WDDX

Автор: content Понедельник, Апрель 9th, 2012 Нет комментариев

Рубрика: Язык PHP

В статье рассматривается методика организации кроссплатформенного межзадачного обмена данными на основе XML с применением WDDX-пакетов. Приведенные примеры демонстрируют возможность как формирования входных документов, так и загрузки массивов в формате XML+WDDX в PHP-приложение.
Одна из весьма серьезных проблем, возникающих при Web-программировании заключается в необходимости стыковки между расличными задачами (программами), объединяемыми в Internet/Intranet-систему. Например, при разработке сложных систем, которые ведутся в несколько этапов различными коммандами разработчиков, может возникнуть ситуация, при которой часть модулей реализована на Perl, а часть — на PHP.
Достаточно удобное решение возникающих в такой ситуации многочисленных проблем, которое было предложено фирмой Allaire, разработчиком известной инструментальной системы Gold Fusion, основано на формате XML. А точнее на одном из его расширений.
WDDX (Web Distributed Data eXchange — обмен данными, распределенными в сети), является производным от XML и предоставляет достаточно удобный механизм, позволяющий конвертировать структуры данных из Perl, Javascript или PHP в некоторый унифицированный формат на базе XML или обратно. (В отличие от пакета Gold Fusion, WDDX выпущен как проект с открытым кодом. Вы можете загрузить WDDX SDK с сервера http://www.openwddx.org. А при необходимости обеспечить работу с WDDX из программы на Perl, воспользуйтесь модулем WDDX.pm с CPAN.)

1. Первое знакомство с WDDX

Главное преимущество WDDX заключается в прозрачной для программиста поддержке не только разнообразных «элементарных» типов данных: строк, чисел, логических значений, даты и времени, но и составных — массивов, структур и записей. Кроме того, WDDX позволяет представлять и двоичные данные, например, графические изображения. Естественно, поддерживается как вывод, так и ввод данных.
По умолчанию, поддержка WDDX в PHP отключена, чтобы ее активизировать и иметь возможность проверить работоспособность примеров этой статье, вы должны перекомпилировать PHP-машину с конфигурационным ключом —enable-wddx.
После перезагрузки WWW-сервера с поддержкой WDDX мы можем приступить к изучению возможностей этого протокола. Вначале попробуем сериализировать (преобразовать в формат, пригодный для обмена) одно отдельное значение. Хитрость WDDX, которая находит отражение в терминологии, состоит в том, что исходные данные преобразуются в так называемые «пакеты данных», которые инкапсулируют имя переменной, её тип и значение.
Поэтому приведенная ниже программа:

<?php
print wddx_serialize_value(«Преобразование PHP в WDDX», «PHP пакет»);
?>

приведет к формированию пакета (текстовой строки):

<wddxPacket version=’1.0′>
<header comment=’PHP пакет’/>
<data>
<string>
Преобразование РНР в WDDX
</string>
</data>
</wddxPacket>

Итак, что мы видим… Вначале в поток помещен тэг, представляющий собой идентификатор версии протокола WDDX. Версия 1.0 является единственной существующей, поэтому просто принимайте эту информацию к сведению. Затем следует комментарий, в котором содержится либо описание переменной, либо иногда помещается имя переменной, в которой хранились данные в исходной программе. А уже затем следует тэг (в данном случае <string>), который определяет тип переменной и её значение.
Но использовать WDDX для хранения отднльных, изолированных переменных на практике не слишком удобно. Поэтому в WDDX предусмотрен механизм «накопления» переменных, подлежащих сериализации, с последующим помещением их «в один флакон». Вот как это выглядит на практике:

<?php
$pi = 3.1415926;
// Создаем пакет, в который будем сбрасывать данные
// Сразу же определяем его заголовок, в котором обычно
// помещается назначенние и/или происхождение пакета
$packet_id=wddx_packet_start(«PHP»);
// добавляем первую переменную
wddx_add_vars($packet_id,«pi»);

// А теперь определим массив $cities
$cities=array(«Austin», «Novato», «Seattle»);
// и тоже сбросим его в пакет
wddx_add_vars($packet_id, «cities»);

// теперь закрываем (и формируем) пакет
$packet=wddx_packet_end($packet_id);
// это большая строка, в которой содержится все
// помещенные в пакет переменные
print $packet;
?>

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

<wddxPacket version=’1.0′><header comment=’PHP’/>
<data>
<struct>
<var name=’pi’><number>3.1415926</number>
</var>
< name=’cities’>
<array length=’3′>
<string>Austin</string>
<string>Novato</string>
<string>Seattle</string>
</array>
</var>
</struct>
<data>
<wddxPacket>

2. Функции WDDX-генератора и анализатора

Теперь давайте приступим к подобному обсуждению функций WDDX.

2.1 Сериализация переменной — wddx_serialize_value

string wddx_serialize_value (mixed var [, string comment])

Функция wddx_serialize_value() используется для создания WDDX пакета, содержащего одно единственое значение. Это значение извлекается из переменной var, а при наличии необязательного комментария comment, он добавляется в заголовок пакета. Результатом работы функции является сформированный WDDX-пакет.

2.2 Сериализация множества — wddx_serialize_vars

string wddx_serialize_vars (mixed var_name [, mixed ...])

Функция wddx_serialize_vars() предназначена для создания пакета WDDX, в котором содержится структура с сериализованным представлением множества переменных, переданный в качестве аргументов функции.
Функция принимает переменное количество аргументов, каждый из которых может представлять собой либо строку, значение которойявляется именем переменной, подлежащей помещению в пакет, либо массив, элементы которого являются именами переменных или массивов, которые содержат такие имена и т.д. В общем рекурсивные возможности функции, на которые несомненное влияние оказал Лисп, предоставляют широкий простор для деятельности…
Вот так эта функция может использоваться в прикладной программе:

<?php
$a=1;
$b=5.5;
$c=array(«blue»,«orange»,«violet»);
$d=«colors»;

$clvars=array(«c»,«d»);
print wddx_serialize_vars(«a»,«b»,$clvars);
?>

В результате выполнения этого примера будет сформирован следующий пакет WDDX:

<wddxPacket version=’1.0′>
<header/>
<data>
<struct>
<var name=’a'>
<number>1</number>
</var>
<var name=’b'>
<number>5.5</number>
</var>
<var name=’c'>
<array length=’3′>
<string>blue</string>
<string>orange</string>
<string>violet</string>
<array>
<var>
<var name=’d'>
<string>colors</string>
</var>
</struct>
</data>
</wddxPacket>

2.3 Создание нового пакета — wddx_packet_start

int wddx_packet_start ([string comment])

Функция wddx_packet_start() используется для создания нового пакета WDDX, предназначенного для накопления в нем нескольких переменных. Функция может принимать дополнительный аргумент comment, в который помещается необязательный комментарий (описание пакета). По завершению работы функция возвращает целочисленный идентификатор пакета, который используется при работе функций заполнения. Определение всех необходимых структур данных, необходимых для хранения помещаемых в пакет переменных, будет выполняться автоматически.

2.4 Закрытие пакета — wddx_packet_end

string wddx_packet_end (int packet_id)

Функция wddx_packet_end() завершает обработку пакета WDDX, идентифицируемого с помощью packet_id и возвращает строку, содержащую сформированный пакет.

2.5 Добавление данных в пакет — wddx_add_vars

wddx_add_vars (int packet_id, mixed name_var [, mixed ...])

Функция wddx_add_vars() используется для сериализации переданных ей аргументов с помещением в открытый ранее пакет с идентификатором id. Переменные, которые подлежат сериализации, определяются так же, как и в функции wddx_serialize_vars().

2.6 Восстановление данных — wddx_deserialize

mixed wddx_deserialize (string packet)

Функция wddx_deserialize() принимает в качестве аргумента строку, содержащую пакет WDDX, анализирует ее и восстанавливает переменные, содержащиеся в ней. Возвращаемый результат может представлять собой строку, число или массив. Сложные структуры данных при восстановлении помещаются в ассоциативные массивы.

3. Генерация системного журнала в XML+WDDX

Теперь, в качестве иллюстрации, рассмотрим практический пример работы подсистемы обработки ошибок в РНР (Листинг 1). Мы создадим собственную функцию обработчика ошибок, которая будет генерировать журнал, представленный в модном XML-формате, а также отправлять письмо администратору узла при обнаружении критических ошибок. Поскольку нам придется иметь дело с массивами, для их помещения в журнал мы воспользуемся WDDX.
Возможно, пример покажется вам достаточно длинным, но, поверьте, дело того стоит…
Состоит он из двух основных частей — формирования журнала и его последующего просмотра. Поскольку пользователь nobody, от имени которого обычно запускаются PHP-программы на сервере Apache, не имеет особых прав на работу с файловой системой, для размещения системного журнала мы будем использовать каталог tmp. В некоторых версиях Linux доступ на запись в этот каталог «посторонним» пользователям закрыт. Поэтому вам может потребоваться изменить права доступа к нему с помощью команды (такая комманда — это грубейшее нарушение безопасности и не рекомендуется проводить на узлах, подключенных с сети Интернет)
chmod a+w /tmp
Обратите внимание на команду unlink в самом начале программы. Дело в том, что XML-документ может содержать только один элемент верхнего уровня, а команда error_log осуществляет \textit{дописывание в конец существующего файла}. Поэтому, если вы не будете создавать системный журнал заново, то выполнить программу больше одного раза просто не сможете — анализатор XML аварийно завершит работу при обнаружении второго документа верхнего уровня.
После этого мы создаем новый файл журнала и помещаем в него открывающий тег <ERRORLOG>. Затем устанавливаем свой собственный обработчик ошибочных ситуаций, в задачу которого входит сформировать запись в XML-формате, которая будет записана в журнал.
До тех пор, пока структура записи определена достаточно жестко:

<ERRORLOG>
<ERRORENTRY>

<DАТЕТIМЕ>Дата и время события</DАТЕТIМЕ>
<ERRORNUM>Koд ошибки</ERRОRNUM>
<ERRORTYPE>Kaтeгopия</ERRORTYPE>
<ERRORMSG>Cooбщeнue об ошибке</ЕRRОRMSG>
<SСRIРТNAМЕ>Файл. в котором зафиксирована ошибка</SСRIРТNAМЕ>
<SCRIPTLINENUM>Hoмep строки в <j>aline</SCRIPTLINENUM>

</ERRORENTRY>

И никакой необходимости в использовании WDDX не возникает. Эти данные без особых проблем считываются и разбираются анализатором XML. Но в некоторых ситуациях нам бы хотелось, чтобы в системный журнал наряду с текстом сообщения об ошибках помешались также значения переменных, действующих на момент возникновения этой ошибки. Стандартный механизм обработки ошибочных ситуаций PHP-машины этой информации нам не дает.
Но мы сможем справиться с этой проблемой и самостоятельно… Для этого нам достаточно всего трех строчек:

$еrr .= «\t<VARTRACE>«:
$err .= wddx_serialize_value($vars,«Variables»);
$err .= «</VARTRACE>\n»;

В результате мы создаем собственный элемент XML-документа <VARTRACE>. внутри которого поместим WDDX-пакет, составленный из списка локальных переменных (аргумент $vars, определенных в процедуре в момент обнаружения ошибки. Понятно, что и имена, и значения этих переменных будут меняться от функции к функции и от ошибки, к ошибке. Но для нас важно другое — РНР-машина автоматически формирует WDDX-пакет (который представлен в унифицированном, кроссплатформенном формате) и затем помещает его в выходной файл. В результате мы получаем запись вида:

<ERRORENTRY>
<DATETIME>09-Aug-2001 10:44:42</DATETIME>
<ERRORNUM>512</ERRORNUM>
<ЕRRORTYPE>Предупрехдение пользователя</ЕRRORTYPE>
<ERRORMSG>2-я координата вектора 1 не является чиспом</ERRORMSG>
<SCRIPTNAME>/usr/local/apache/htdocs/php/part2/error-proc.php</SCRIPTNAME>
<SCRIPTLINENUM>107</SCRIPTLINENUM>
<VARTRACE><wddxPacket version=’1.0′>
<header>
<comment>Variables</comment>
</header>
<data>
<struct>
<var name=’vect1′ >
<array length=’3′>
<number>2</number>
<number>3</number>
<string>foo</string>
</array>
</var>
<var name=’vect2′>
<array length=’3′>
<number>5.5</number>
<number>4.3</number>
<number>-1.6</number>
</array>
</var>
<var name=’i'>
<number>2</number>
</var>
<var name=’c1′>
<string>foo</string>
</var>
<var name=’c2′>
<number>-1.6</number>
</var>
<var name=’d'>
<number>0</number>
</var>
</struct>
</data>
</wddxPacket>
</VARTRACE>
</ERRORENTRY>

Как видите, WDDX-пакет органично помещается внутрь XML-документа, что одновременно и хорошо, и плохо. Хорошо с той точки зрения, что позволяет аккуратно закруглить (как это сделано в большинстве книг и руководств по РНР) обсуждение вопроса, заявив, что использование функции wddx_desrialize() автоматически решит все ваши проблемы. А плохо потому, что это на самом деле не так, и анализ XML-документа со встроенными пакетами WDDX реализуется не столь прямолинейно, как нам хотелось бы.
Собственно говоря, именно поэтому в рассматриваемый нами пример я включил и собственную версию анализатора на базе библиотеки Expat, ориентированную именно на обработку сгенерированного нами файла.
Проблема заключается именно в том, что теги WDDX ничем по сути не отличаются от тегов XML, a следовательно, они будут автоматически обрабатываться обработчиками событий. Но так ли это здорово на самом деле? Ведь чтобы разобрать XML-документ с вложенными WDDX-пакетами вам потребуется фактически самостоятельно реализовать обработку тегов WDDX внутри анализатора? При этом вам не удастся «просто так» получить исходный код пакета, который можно одним вызовом функции превратить в структуру данных, аналогичную той, которая использовалась для синтеза пакета. Но разве мы за это боролись?
Единственное достаточно компактное решение состоит в том, что мы в процессе анализа восстанавливаем текст WDDX-пакета со всеми его атрибутами, а после завершения его сборки (о чем нам сигнализирует тег </VARTRACE>) мы разбираем полученный нами пакет функцией wddx_deserialize, а уже затем извлекаем из нее список переменных и их значения.
Как видите, нам удалось реализовать механизм отладки программы, который позволяет старым добрым методом контрольной печати вскрыть практически любые ошибки времени исполнения программ. Но гораздо важнее, что теперь в вашем распоряжении имеется механизм, позволяющий полностью реализовать межзадачный обмен данными — как из приложения на РНР, так и загрузить данные из внешнего мира.
Литература

o [Vodolaz2000] В.Барсуков, В.Водолазкий Интегральная безопасность в системах и сетях передачи данных. М.: Knowledge, 2000, 450 стр.
o [Vodolaz2001] В.Водолазкий, А.Колядов Путь к Linux, изд. 2-е, М.: Knowledge, 2001, 560 стр.
o [XML2000] Н.Питц-Моултис, Ч.Кирк XML: Современная технология создания документов для Internet — С-Пб.: БХВ-Петербург, 2000, 736 стр.
o [php2001] Т.Ратшиллер, Т.Геркен РНР4: Разработка Web-приложений, С-Пб.: Питер, 2001, 384 стр.
o [Huews-2001] С.Хьюз, А.Змиевский РНР. Руководство разработчика, К.: Diasoft, 2001, 380 стр.
Листинг 1. Пример программы, генерирующей системный журнал.

<HTML>
<ТITLE>Генератор системного журнала в ХМL-Формате</ТITLE>
<BODY BGCOLOR=«#FFFFFF»>
<hЗ>Демонстрация работы пользовательского обработчика ошибок</hЗ>
В этой программе осуществляется формирование
пользовательского системного журнала, который располагается в
каталоге <b>/tmp</b>. Формат системного журнала — XML+WDDX.<p>

<h4>Первый этап — генерация журнала</h4>
<?рhр

$sysadmin = «root@1ocalhost»; // адрес администратора системы,
// который получает сообщение об ошибке в программе

@unlink(«/tmp/errorlog.txt»); // прежний журнал не нужен
// Закрываем префиксом @ для предотвращения генерации сообщения
// при отсутствии такого файла

// Вначале открываем сеанс для записи
error_log(«<ERRORLOG>\n».3.«/tmp/errorlog.txt»);

// И вводим свой собственный обработчик ошибок
function userErrorHandler ($errno, $errmsg, $filename, $linenum, $vars){
// Формат отображения времени о журнале в память об
// операционной системе РАФОС (RT-11)
$dt = date(«d-M-Y H:i:s»);

// теперь создадим хэш-массив с кодами и категориями
// сообщений об ошибках
$errortype = array (
1 => «Ошибка».
2 => «Предупреждение»,
4 => «Ошибка компилятора»,
8 => «Подсказка»,
16 => «Ошибка РНР-машины»,
32 => «Предупреждение РНР-машины»,
64 => «Ошибка компилятора»,
128 => «Предупреждение компилятора»,
256 => «Ошибка пользователя»,
512 => «Предупреждение пользователя»,
1024 => «Подсказка пользователя»
);
// Сформируем маску отслеживаемых событий
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);

// теперь сформируем XML-запись сообщения об ошибке
// Поскольку формат прост, мы не будем использовать DOM-модель
// с автоматической генерацией документа…

$err =«<ERRORENTRY>\n .
$err.=»
<DATETIME>«.$dt</DATETIME>\n«;
$err.=»
<ERRORNUM>«.$errno</ERRORNUM>\n«;
$err.=»
<ERRORTYPE>«.$errortype[$errno].»</ERRORTYPE>\n«;
$err.=»
<ERRORMSG>«.$errrmsg</ERRORMSG>\n«;
$err.=»
<SCRIPTNAME>» $filename</SCRIPTNAME>\n«:
$err.=»
<SCRIPTLINEMUM>«.$linenum</SCRIPTLINENUM>\n«;

if (in_array($errno, $user_errors))
{
// Массив преобразуем с помощьо WODX
$err = «\t<VARTRACE>«;
$err.= wddx_serialize_value($vars, «
Variables«);
$err.= «
</VARTRACE>\n«;
}

$err.= «</ERRORENTRY>\n\n«;

// тестовая печать в процессе отладки программы
// echo «<pre>$err</pre><p>«;

// теперь помешаем сформированную запись в журнал, и если
// это критическая ошибка, генерируем сообщение системному
// администратору
error_log($err, 3, «/tmp/errorlog.txt«);
if ($errno == E_USER_ERROR)
mail($sysadmin, «
Критическая ошибка в программе!«.$err);

}

// Функция, вычисляющая расстояние между двумя векторами.
// которая генерирует немало сообщений об ошибках
function distance ($vect1, $vect2) {

if (is_array($vect1) || !is_array($vect2)) {
trigger_error(«Недопустимый тип аргументов!«,
E_USER_ERROR);
return NULL;
}

if (count($vect1) != count($vect2)) {
trigger_error(«Векторы должны иметь одинаковый размер«,
E_USER_ERROR);
return NULL;
}

for ($i=0; $i<count($vect1); $i++) {
$c1 = $vect1[$i];
$c2 = $vect2[$i];
$d = 0.0;

if (!is_numeric($c1)) {
trigger_error(«$i-я координата вектора 1
не является числом«,E_USER_WARMING);
$c1 = 0.0;
}

if (!is_numeric($c2)) {
trigger_error(«$i-я координата вектора 2
не является числом«, E_USER_WARNING);
$c2 = 0.0;
}

$d += $c2*$c2$c1*$c1.
}
return sqrt($d);
}

// переустанавливаем обработчик ошибок
$old_error_handler = set_error_handler(«userErrorHandler«);

?>

<ul>
<li>Неопределенная константа — сформирует сообщение об ошибке

<?
$t = I_AM_NOT_DEFINED;

// теперь создадим несколько векторов
$а = array(2.3, «foo«);
$b = array(5.5, 4.3, -1.6);
$c = array (1,-3);

?>

<li>Генерируем сообщение об ошибке при вычислении функции
<?
$t1 = distance($c,$b).»\n«;
?>

<li> и еще одно — о неверных аргументах
<?
$t2 = distance($b,»А я не массив…«).»\n«;
?>

<li>А в заключение, сгенерируем предупреждение…
<?
$t3 = distance($a,$b).»\n«;

// Восстановим системный обработчик
restore_error_handler($old_error_handler);
error_log(«</ERRORLOG>\n«,3,»/tmp/errorlog.txt«);

?>
</ul>
<h4>Восстанавливаем содержимое журнала и выводим его в виде таблицы</h4>

<?
class logger {
var $xml_parser;
var $xml_file;
var $html;
var $open_tag;
var $close_tag;
var $wddx_flag; // флажок обнаружения WDDX-пакета
var $wddx; // поток WDDX-данных (сборка пакета)

// Конструктор класса
function logger () {
$this->xml_parser = ««;
$this->xml_file = «
«;
$this->html = «
«;
$this->wddx_flag = 0;
$this->wddx = «
«;
$this->open_tag = array(
// Настраиваем интерпретатор отдельных
// тегов нашего заказного формата
«
ERRORLOG» => «<TABLE CELLPADDING=5>«,
«
ERRORENTRY» => «<TR><TD BGCOLOR=#f2f2f2>«.
«
DATETIME» => «<FONT COLOR=#883800>«,
«
ERRORNUM» => «<TD 8GCOLOR=#f2f2f2>«,
«
Код ошибки: <FONT COLOR=#000A0C<B> «,
«
ERRORTYPE» => «Категория ошибки: <FONT COLOR=#3F3F00>«,
«
ERRORMSG» => ‘<FONT SIZE=-1><FONT COLOR=#D22323>»,
«SCRIPTNAME» => «<р>Файл: «,
«SCRIPTLINENUM» => «строка — <B>«,
«VARTRACE» => «<p><FONT COLOR=\»BLUE\«>Пepeмeнныe:»);

// а здесь — закрывавшие теги
$this->close_tag = array(
«ERRORLOG» => «</TABLE>\n\n»,
«ERRORENTRY» => «</TD></TR>«,
«DATETIME» => «</FONT></TD>«,
«ERRORNUM» => «</B>«,
«ERRORTYPE» => «<br>«,
«ERRORHSG» => «</FONT></FONT>«,
«SCRIPTNAME» => » «,
«SCRIPTLINENUM => «</B>«,
«
VARTRACE» => «</FONT> «);
}

// Деструктор класса. В отличие от Си++ и Perl его
// необходимо вызывать вручную
function destroy() {
xml_parser_free( $this->xml_parser);
}

//Основные функции введенного нами класса
function concat($str) {
// дописывает в генерируемый HTML-поток очередную строку
$this-> html .= $str;
}

// Вызывается при начале нового элемента в документе
function startElement( $parser, $name. $attrs) {

if ($format= $this->open_tag[$name]) {
$this-> html .= $format;
}

if ($name == «VARTRACE«) {
$this->wddx_flag = 1;
$this->wddx = «
«:
} else
if ($this->wddx_fiag == 1) {
$this->wddx .= «
<«.$name «; // открываем тег
// теперь обрабатываем его аргументы (атрибуты)
while (list ($key, $val) = each($attrs)) {
$this->wddx .= $key
=’«.$val«;
}
$this->wddx .= «
>«;
}
}
}
// Вызывается при окончании обработки элемента
function endElement($parser, $name ){
global $close_tag;
if ($format= $this->close_tag[$name]){
$this->html .= $format;
}
if ($name == «
VARTRACE«){
$this->wddx_flag = 0;
$m = wddx_deseriali2e($this->wddx);
// отладочная печать
// echo «<pre>«.$this->wddx.»</pre>«;
// var_dump($m);
while (list ($key,$val) = each($m)){
// Добавляем в поток HTML информацию о переменных
$this->html.= «
Аргумент <font color=\«black\»>«;
$this->html.= «
<b>«.$key</b></font>: «;
if (is_array($val)){
$this->html.= implode(‘,’,$val);
}
else{
$this->html.= $val;
}
$this->html.= «
«;
}
}
if ($this->wddx_flag == 1){
$this->wddx.=»
</«.$name>«;
}
}

// Обработчик символьных данных СDАТА
function characterData ($parser, $data ) {
// во избежание недомолвок
if ($this->wddx_flag == 1) {
this->wddx.= $data;
}
else{
$this->html.= $data;
}
}

// Разбор файла
function parse() {
$this->xml_parser= xml_parser_create();
xml_set_object($this->xml_parser, &$this);
// обратите внимание на нивелирование регистров тегов
// что позволяет при лобом раскладе установить соответствие
// их с записями $mар_аrrау
xml_parser_set_option($this->xml_parser,
XML_OPTION_CASE_FOLDING, false );
xml_set_element_handler($this->xml_parser,
«startElement«, «endElement«);
xml_set_character_data_handler($this->xml_parser,»
characterData«);

if (!($fp = fopen($this->xml_file,»r«))) {
die(«
He могу открыть входной файл XML«);
}

while ($data = fread($fp, 4096)) {
if (!xml_parse($this->xml_parser, $data, feof($fp))) {
die(sprintf(«Ошибка в XML файле : %s на строке %d«,
xml_error_string( xml_get_error_code(
$this->xml_parser )),
хml_get_current_line_number($this->xml_parser)));
}
}
}

$log = new_logger();
$log->xml_file =»/tmp/errorlog.txt«;
$log->parse();
print ($log->html);

$log->destroy();

?>

Автор: Владимир Водолазкий, к.т.н.

Источник: http://www.php.su/articles/?cat=xml&page=007

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты