Не такой простой SAX парсер
От: WinterMute Россия http://yarrr.ru
Дата: 13.07.06 20:45
Оценка: 6 (1) :)
SAX-велосипед: (дисковые тормоза, рама -- карбон...)

По мотивам сканера c-smile'а
Автор: c-smile
Дата: 10.09.04
.

Строго говоря, "SAX-парсер" это весьма громкое название для этой библиотеки, но она позволяет решить, наверное, все задачи которые решает настоящий SAX-парсер, а всё остальное может выполнить вызывающая сторона.

Это не валидирующий парсер, т.е. правильный документ он поймёт правильно, неправильный он как-то поймёт. Проверка на корректность имён не производится. Единственным строгим требованием к обработке некорректного документа было: "не подвесить на нём программу".

Основные отличия от парсера c-smile'а:

Известное ограничение: не парсится !DOCTYPE и вложенные в него секции, такие как !ENTITY, !ELEMENT и т.д. В настоящий момент, на ветках, которые должны обрабатывать эти потоки стоят заглушки. Мне пока не нужны, а их поддержка раздует код ещё больше.


Пример использования:

#include "../xml/sax/sax.h"

namespace xml
{
namespace sax
{

// Поток ввода
class sax_stream: public entity_stream
{
    size_t length( const xml::char_t* p )
    {
        for( size_t i = 0; ; i++ ) if( 0 == p[i] ) return i;
        return -1;
    }

    const xml::char_t* m_p;
    const xml::char_t* m_end;

public:
    sax_stream( const xml::char_t* src ): m_p(src), m_end(src + length(src)) {}

    virtual xml::char_t  pop_char() { return *m_p++: }
    virtual bool         has_data() const { return m_p < m_end; }
    virtual entity_type  type() const { return ET_XML; }
    virtual int          id() const { return 0; }
};

class sax_callback : public callback
{
public:
    sax_callback(){}

    virtual void document_start() { wprintf(L"\nDOC START ------\n\n"); }
    virtual void document_end()   { wprintf(L"\nDOC END   ------"); }

    virtual void element_start( const scanner& scan ) { wprintf(L"\nEL START: <%s", scan.el_name().p() ); }
    virtual void element_end( const scanner& scan )   { wprintf(L"\nEL END:   </%s", scan.el_name().p() ); }

    virtual void pi_start( const scanner& scan ) { wprintf( L"\n<?%s:", scan.el_name().p() ); }
    virtual void pi_end( const scanner& scan )   { wprintf( L"?>" ); }

    // ...

    virtual void character( char_t c ) { wprintf(L"%c",c); }

    virtual bool resolve_entity( const str_t& name, str_t& result, entity_type& type, int& id )
    {
        if( name.length() == 4 )
        {
            if( str_eq( name, L"wow1", 4 ) )
            {
                result.set( L"-&wow2;-", 8 );
                type = ET_XML;
                id = 1;
                return true;
            }
            if( str_eq( name, L"wow2", 4 ) )
            {
                result.set( L"<win>", 5 );
                type = ET_TXT;  // Будет вставлено как текст
                id = 0; // text stream id
                return true;
            }
        }

        return false;
    }
};

}
}

int _tmain(int argc, _TCHAR* argv[])
{
    xml::sax::sax_stream  my_stream( L"<?xml version='1.0' encoding='utf-8'?>"
                                     L"W&amp;amp &wow1; &wow2; <preved>Medved</preved>" );

    xml::sax::scanner  scan( xml::sax::sax_callback() );

    scan.parse( my_stream );

    return 0;
}



Исходники и демонстрационный проект: http://yarrr.ru/dl/xml_sax.zip (29K)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.