PHP4/PHP5. Simple Application Programming Interface for XML. SAX-parser

Во-первых, 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 &quot;hard&quot;.</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.