mirror of https://github.com/vitalif/grive2
refactored to allow progressive parsing
parent
19c329836b
commit
b89f7bb873
|
@ -25,20 +25,33 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace gr { namespace xml {
|
namespace gr { namespace xml {
|
||||||
|
|
||||||
TreeBuilder::TreeBuilder() : m_stack( 1, Node() )
|
struct TreeBuilder::Impl
|
||||||
|
{
|
||||||
|
std::vector<Node> stack ;
|
||||||
|
::XML_Parser psr ;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
TreeBuilder::TreeBuilder() : m_impl( new Impl )
|
||||||
|
{
|
||||||
|
m_impl->stack.push_back( Node() ) ;
|
||||||
|
m_impl->psr = ::XML_ParserCreate( 0 ) ;
|
||||||
|
|
||||||
|
::XML_SetElementHandler( m_impl->psr, &TreeBuilder::StartElement, &TreeBuilder::EndElement ) ;
|
||||||
|
::XML_SetUserData( m_impl->psr , this ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeBuilder::~TreeBuilder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Node TreeBuilder::ParseFile( const std::string& file )
|
Node TreeBuilder::ParseFile( const std::string& file )
|
||||||
{
|
{
|
||||||
::XML_Parser p = ::XML_ParserCreate( 0 ) ;
|
|
||||||
::XML_SetElementHandler( p, &TreeBuilder::StartElement, &TreeBuilder::EndElement ) ;
|
|
||||||
|
|
||||||
TreeBuilder tb ;
|
TreeBuilder tb ;
|
||||||
::XML_SetUserData( p, &tb ) ;
|
::XML_Parser p = tb.m_impl->psr ;
|
||||||
|
|
||||||
std::ifstream f( file.c_str() ) ;
|
std::ifstream f( file.c_str() ) ;
|
||||||
|
|
||||||
|
@ -48,22 +61,26 @@ Node TreeBuilder::ParseFile( const std::string& file )
|
||||||
XML_ParseBuffer( p, count, false ) ;
|
XML_ParseBuffer( p, count, false ) ;
|
||||||
XML_ParseBuffer( p, 0, true ) ;
|
XML_ParseBuffer( p, 0, true ) ;
|
||||||
|
|
||||||
assert( tb.m_stack.size() == 1 ) ;
|
return tb.Result() ;
|
||||||
return tb.m_stack.front() ;
|
}
|
||||||
|
|
||||||
|
void TreeBuilder::ParseData( const char *data, std::size_t count, bool last )
|
||||||
|
{
|
||||||
|
if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 )
|
||||||
|
throw std::runtime_error( "XML parse error" ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node TreeBuilder::Parse( const std::string& xml )
|
Node TreeBuilder::Parse( const std::string& xml )
|
||||||
{
|
{
|
||||||
::XML_Parser p = ::XML_ParserCreate( 0 ) ;
|
|
||||||
::XML_SetElementHandler( p, &TreeBuilder::StartElement, &TreeBuilder::EndElement ) ;
|
|
||||||
|
|
||||||
TreeBuilder tb ;
|
TreeBuilder tb ;
|
||||||
::XML_SetUserData( p, &tb ) ;
|
tb.ParseData( xml.c_str(), xml.size(), true ) ;
|
||||||
|
return tb.Result() ;
|
||||||
|
}
|
||||||
|
|
||||||
XML_Parse( p, xml.c_str(), xml.size(), true ) ;
|
Node TreeBuilder::Result() const
|
||||||
|
{
|
||||||
assert( tb.m_stack.size() == 1 ) ;
|
assert( m_impl->stack.size() == 1 ) ;
|
||||||
return tb.m_stack.front() ;
|
return m_impl->stack.front() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeBuilder::StartElement( void *pvthis, const char *name, const char **attr )
|
void TreeBuilder::StartElement( void *pvthis, const char *name, const char **attr )
|
||||||
|
@ -74,7 +91,7 @@ void TreeBuilder::StartElement( void *pvthis, const char *name, const char **att
|
||||||
|
|
||||||
TreeBuilder *pthis = reinterpret_cast<TreeBuilder*>(pvthis) ;
|
TreeBuilder *pthis = reinterpret_cast<TreeBuilder*>(pvthis) ;
|
||||||
|
|
||||||
Node n = pthis->m_stack.back().AddElement( name ) ;
|
Node n = pthis->m_impl->stack.back().AddElement( name ) ;
|
||||||
|
|
||||||
for ( std::size_t i = 0 ; attr[i] != 0 ; i += 2 )
|
for ( std::size_t i = 0 ; attr[i] != 0 ; i += 2 )
|
||||||
{
|
{
|
||||||
|
@ -82,15 +99,15 @@ void TreeBuilder::StartElement( void *pvthis, const char *name, const char **att
|
||||||
n.AddAttribute( attr[i], attr[i+1] ) ;
|
n.AddAttribute( attr[i], attr[i+1] ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthis->m_stack.push_back( n ) ;
|
pthis->m_impl->stack.push_back( n ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeBuilder::EndElement( void* pvthis, const char* name )
|
void TreeBuilder::EndElement( void* pvthis, const char* name )
|
||||||
{
|
{
|
||||||
TreeBuilder *pthis = reinterpret_cast<TreeBuilder*>(pvthis) ;
|
TreeBuilder *pthis = reinterpret_cast<TreeBuilder*>(pvthis) ;
|
||||||
|
|
||||||
assert( pthis->m_stack.back().Name() == name ) ;
|
assert( pthis->m_impl->stack.back().Name() == name ) ;
|
||||||
pthis->m_stack.pop_back() ;
|
pthis->m_impl->stack.pop_back() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
} } // end of namespace
|
} } // end of namespace
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace gr { namespace xml {
|
namespace gr { namespace xml {
|
||||||
|
|
||||||
|
@ -29,17 +29,24 @@ class Node ;
|
||||||
class TreeBuilder
|
class TreeBuilder
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
TreeBuilder() ;
|
||||||
|
~TreeBuilder() ;
|
||||||
|
|
||||||
|
void ParseData( const char *data, std::size_t count, bool last = false ) ;
|
||||||
|
Node Result( ) const ;
|
||||||
|
|
||||||
|
// one shot helpers
|
||||||
static Node ParseFile( const std::string& file ) ;
|
static Node ParseFile( const std::string& file ) ;
|
||||||
static Node Parse( const std::string& xml ) ;
|
static Node Parse( const std::string& xml ) ;
|
||||||
|
|
||||||
private :
|
private :
|
||||||
TreeBuilder() ;
|
|
||||||
|
|
||||||
static void StartElement( void* pvthis, const char* name, const char** attr ) ;
|
static void StartElement( void* pvthis, const char* name, const char** attr ) ;
|
||||||
static void EndElement( void* pvthis, const char* name ) ;
|
static void EndElement( void* pvthis, const char* name ) ;
|
||||||
|
|
||||||
private :
|
private :
|
||||||
std::vector<Node> m_stack ;
|
struct Impl ;
|
||||||
|
std::auto_ptr<Impl> m_impl ;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
} } // end of namespace
|
} } // end of namespace
|
||||||
|
|
Loading…
Reference in New Issue