blob: 682c04ff7b2e4d9bdfd6da406387e972a8f526fa [file] [log] [blame]
// tiny XML sub-set tools implementation -----------------------------------//
// (C) Copyright Beman Dawes 2002. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "tiny_xml.hpp"
#include <cassert>
#include <cstring>
namespace
{
void eat_whitespace( char & c, std::istream & in )
{
while ( c == ' ' || c == '\r' || c == '\n' || c == '\t' )
in.get( c );
}
std::string get_name( char & c, std::istream & in )
{
std::string result;
eat_whitespace( c, in );
while ( std::strchr(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.", c )
!= 0 )
{
result += c;
if(!in.get( c ))
throw std::string("xml: unexpected eof");
}
return result;
}
void eat_delim( char & c, std::istream & in,
char delim, const std::string & msg )
{
eat_whitespace( c, in );
if ( c != delim )
throw std::string("xml syntax error, expected ") + delim
+ " (" + msg + ")";
in.get( c );
}
std::string get_value( char & c, std::istream & in )
{
std::string result;
while ( c != '\"' )
{
result += c;
in.get( c );
}
in.get( c );
return result;
}
}
namespace boost
{
namespace tiny_xml
{
// parse -----------------------------------------------------------------//
element_ptr parse( std::istream & in, const std::string & msg )
{
char c = 0; // current character
element_ptr e( new element );
if(!in.get( c ))
throw std::string("xml: unexpected eof");
if ( c == '<' )
if(!in.get( c ))
throw std::string("xml: unexpected eof");
e->name = get_name( c, in );
eat_whitespace( c, in );
// attributes
while ( c != '>' )
{
attribute a;
a.name = get_name( c, in );
eat_delim( c, in, '=', msg );
eat_delim( c, in, '\"', msg );
a.value = get_value( c, in );
e->attributes.push_back( a );
eat_whitespace( c, in );
}
if(!in.get( c )) // next after '>'
throw std::string("xml: unexpected eof");
eat_whitespace( c, in );
// sub-elements
while ( c == '<' )
{
if ( in.peek() == '/' ) break;
e->elements.push_back( parse( in, msg ) );
in.get( c ); // next after '>'
eat_whitespace( c, in );
}
// content
if ( c != '<' )
{
e->content += '\n';
while ( c != '<' )
{
e->content += c;
if(!in.get( c ))
throw std::string("xml: unexpected eof");
}
}
assert( c == '<' );
if(!in.get( c )) // next after '<'
throw std::string("xml: unexpected eof");
eat_delim( c, in, '/', msg );
std::string end_name( get_name( c, in ) );
if ( e->name != end_name )
throw std::string("xml syntax error: beginning name ")
+ e->name + " did not match end name " + end_name
+ " (" + msg + ")";
eat_delim( c, in, '>', msg );
return e;
}
// write ---------------------------------------------------------------//
void write( const element & e, std::ostream & out )
{
out << "<" << e.name;
if ( !e.attributes.empty() )
{
for( attribute_list::const_iterator itr = e.attributes.begin();
itr != e.attributes.end(); ++itr )
{
out << " " << itr->name << "=\"" << itr->value << "\"";
}
}
out << ">";
if ( !e.elements.empty() )
{
out << "\n";
for( element_list::const_iterator itr = e.elements.begin();
itr != e.elements.end(); ++itr )
{
write( **itr, out );
}
}
if ( !e.content.empty() )
{
out << e.content;
}
out << "</" << e.name << ">\n";
}
} // namespace tiny_xml
} // namespace boost