#if !defined( INCLUDED_XML_XMLWRITER_H ) #define INCLUDED_XML_XMLWRITER_H #include "convert.h" #include #include "xml/ixml.h" class BufferedTextOutputStream : public TextOutputStream { enum { m_bufsize = 1024 }; // aka const std::size_t m_bufsize = 1024; TextOutputStream& m_ostream; char m_buffer[m_bufsize]; char* m_pos; const char* m_end; const char* end() const { return m_end; } void reset(){ m_pos = m_buffer; } void flush(){ m_ostream.write( m_buffer, m_pos - m_buffer ); reset(); } public: BufferedTextOutputStream( TextOutputStream& ostream ) : m_ostream( ostream ), m_pos( m_buffer ), m_end( m_buffer + m_bufsize ){ } ~BufferedTextOutputStream(){ flush(); } void write( const char c ){ if ( m_pos == end() ) { flush(); } *m_pos++ = c; } std::size_t write( const char* buffer, std::size_t length ){ const char*const end = buffer + length; for ( const char* p = buffer; p != end; ++p ) { write( *p ); } return length; } }; class XMLEntityOutputStream { BufferedTextOutputStream m_ostream; public: XMLEntityOutputStream( TextOutputStream& ostream ) : m_ostream( ostream ){ } void write( const char c ){ m_ostream.write( c ); } void writeEscaped( const char c ){ switch ( c ) { case '<': write( '&' ); write( 'l' ); write( 't' ); write( ';' ); break; case '>': write( '&' ); write( 'g' ); write( 't' ); write( ';' ); break; case '"': write( '&' ); write( 'q' ); write( 'u' ); write( 'o' ); write( 't' ); write( ';' ); break; case '&': write( '&' ); write( 'a' ); write( 'm' ); write( 'p' ); write( ';' ); break; default: write( c ); break; } } std::size_t write( const char* buffer, std::size_t length ){ const char*const end = buffer + length; for ( const char* p = buffer; p != end; ++p ) { writeEscaped( *p ); } return length; } }; template inline XMLEntityOutputStream& operator<<( XMLEntityOutputStream& ostream, const T& t ){ return ostream_write( ostream, t ); } class XMLStreamWriter : public XMLImporter, public XMLAttrVisitor { class state_t { public: enum EState { eStartElement, eContent, }; state_t() : m_state( eStartElement ) {} EState m_state; }; XMLEntityOutputStream m_ostream; std::vector m_elements; void write_cdata( const char* buffer, std::size_t length ){ m_ostream << ConvertLocaleToUTF8( StringRange( buffer, buffer + length ) ); } void write_string( const char* string ){ m_ostream << string; } void write_quoted_string( const char* string ){ m_ostream.write( '"' ); m_ostream << string; m_ostream.write( '"' ); } public: XMLStreamWriter( TextOutputStream& ostream ) : m_ostream( ostream ){ m_elements.push_back( state_t() ); m_elements.back().m_state = state_t::eContent; m_ostream.write( '<' ); m_ostream.write( '?' ); write_string( "xml" ); visit( "version", "1.0" ); m_ostream.write( '?' ); m_ostream.write( '>' ); } void pushElement( const XMLElement& element ){ if ( m_elements.back().m_state == state_t::eStartElement ) { m_elements.back().m_state = state_t::eContent; m_ostream.write( '>' ); } m_elements.push_back( state_t() ); m_ostream.write( '<' ); write_string( element.name() ); element.forEachAttribute( *this ); } void popElement( const char* name ){ if ( m_elements.back().m_state == state_t::eStartElement ) { m_ostream.write( '/' ); m_ostream.write( '>' ); } else { m_ostream.write( '<' ); m_ostream.write( '/' ); write_string( name ); m_ostream.write( '>' ); } } std::size_t write( const char* data, std::size_t length ){ if ( m_elements.back().m_state == state_t::eStartElement ) { m_elements.back().m_state = state_t::eContent; m_ostream.write( '>' ); } write_cdata( data, length ); return length; } void visit( const char* name, const char* value ){ m_ostream.write( ' ' ); write_string( name ); m_ostream.write( '=' ); write_quoted_string( value ); } }; #endif