Во-первых, SAX не относится к W3C стандарту обработки XML-документов, во-вторых, он относится к семейству потоковых парсеров, то есть данные из XML-документа потоком передаются в парсер и кусками обрабатывается в нем, при этом возможности вернуться и внести изменения не предоставляется.
Парсинг происходит на основе так называемых событий, которые обрабатываются обработчиками. События происходят, когда по ходу обработки документа встречаются открывающие и закрывающие теги, нахождение парсером текстового содержания узла, для обработки которого также определена функция-обработчик. Стоит отметить, что парсер основан на расширении expat (C-шный парсер), который при парсинге документа автоматом переводит имена тегов в верхний регистр, поэтому в функциях-обработчиках стоит использовать имена в верхнем регистре. Не стоит забывать и о кодировке. Все-таки, лучший вариант - utf-8. Ниже приведен скрипт для примера SAX-парсинга новостной ленты.
<?php #SAX-парсинг новостной ленты
/* Инициализация переменных.
Следующая переменная будет служить флагом, который указывает,
находится ли парсер внутри тега item или нет. Только внутри
этого тега находится информация, которую мы хотим получить
из новостной ленты.
*/
$insideitem = false;
/*
Следующие переменные будут использованы для хранения содержания
соответствующих XML-элементов. Эти переменные внутри функций
обработки будут объявлены глобальными.
*/
$tag = "";
$title = "";
$description = "";
$link = "";
/*
Функция обработки открывающего тега принимает в качестве
второго аргумента имя тега и проверяет, не является ли этот тег
тегом item. В случае успеха устанавливает флаг в переменной
$insideitem. Парсер преобразует имена тегов к верхнему регистру,
поэтому их и приходится сравнивать в таком виде.
*/
function startElement($parser, $name, $attrs) {
global $insideitem, $tag, $title, $description, $link;
if ($insideitem) {
$tag = $name;
} elseif ($name == "ITEM") {
$insideitem = true;
}
}
/*
Функция обработки закрывающего тега принимает в качестве второго
аргумента имя тега, проверяет, не является ли этот тег тегом item.
В случае успеха распечатывает данные, накопленные в переменных
$title, $description и $link, а затем присваивает этим переменным
значение "пустая строка". Перед распечаткой значения переменных
обрабатываются функцией trim(), отсекающей пробелы в начале и
конце строки, функцией htmlspecialchars(), обезвреживающей
содержимое элементов, и функцией iconv(), преобразующей данные
в кодировку Windows-1251.
*/
function endElement($parser, $name) {
global $insideitem, $tag, $title, $description, $link;
if ($name == "ITEM") {
$description = htmlspecialchars(trim($description));
$title = htmlspecialchars(trim($title));
printf("<dt><b><a href='%s'>%s</a></b></dt>", trim($link), $title);
printf("<dd>%s</dd>", $description);
$title = "";
$description = "";
$link = "";
$insideitem = false;
}
}
/*
Функция обработки символьного содержимого XML-элемента выполняет
действия только в случае, когда событие происходит внутри тега item,
это определяется по состоянию флага. В случае успеха анализируется,
на каком теге произошло событие, и текстовое содержимое элемента,
переданное функции во втором аргументе, добавляется к значению
соответствующей переменной.
*/
function characterData($parser, $data) {
global $insideitem, $tag, $title, $description, $link;
if ($insideitem) {
switch ($tag) {
case "TITLE":
$title .= $data;
break;
case "DESCRIPTION":
$description .= $data;
break;
case "LINK":
$link .= $data;
break;
}
}
}
// создание парсера
$xml_parser = xml_parser_create();
// задание функций-обработчиков
xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_character_data_handler($xml_parser, "characterData");
/*
Открытие файла RSS-ленты. В случае ошибки сработает оператор die,
вызвающий фукнцию sprintf(), которая распечатает сообщение об ошибке.
*/
$fp = fopen("rss2.xml","r") or die("Error reading RSS data.");
// Чтение четырех килобайтов данных из файла
while ($data = fread($fp, 4096))
// Вызов парсера для обработки данных из файла.
xml_parse($xml_parser, $data, feof($fp))
or die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
// Закрытие файла с данными после того, как он прочитан полностью.
fclose($fp);
// Освобождение ресурсов парсера.
xml_parser_free($xml_parser);
?>
Новостная лента в формате XML-документа (rss2.xml)
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>HardwarePortal.ru: Новости HardwarePortal.ru</title>
<link>http://www.hwp.ru</link>
<description>Portal about computer`s "hard".</description>
<language>en</language>
<lastBuildDate>Mon, 28 Aug 2010 18:14:06 +0400</lastBuildDate>
<webMaster>likeoff@mail.ru</webMaster>
<image>
<title>HardwarePortal.ru</title>
<url>http://hwp.ru/img/logo.gif</url>
<link>http://www.hwp.ru.ru</link>
<width>100</width>
<height>100</height>
<description>HardwarePortal.ru</description>
</image>
<item>
<title>Notebooks</title>
<link>http://hwp.ru/scripts/news_show.php?5717</link>
<description>Fujitsu Siemens released notebooks with fantastic cpu performance</description>
<pubDate>Mon, 28 Aug 2010 16:00:54 +0400</pubDate>
</item>
<item>
<title>Canon</title>
<link>http://hwp.ru/scripts/news_show.php?5692</link>
<description>Canon presents new mirror photo cameras</description>
<pubDate>Thu, 24 Aug 2010 15:57:32 +0400</pubDate>
</item>
<item>
<title>Projector</title>
<link>http://hwp.ru/scripts/news_show.php?5685</link>
<description>Toshiba create new projectors</description>
<pubDate>Thu, 24 Aug 2010 10:34:53 +0400</pubDate>
</item>
</channel>
</rss>
Исходники можно скачать по данной ссылке - download.