|
|
|
@ -49,6 +49,11 @@ namespace xml { |
|
|
|
|
exception::~exception() throw() { |
|
|
|
|
delete _node; |
|
|
|
|
} |
|
|
|
|
void exception::line(unsigned long line) throw() { |
|
|
|
|
std::stringstream ss; |
|
|
|
|
ss<<line; |
|
|
|
|
_what += "\nat line: "+ss.str(); |
|
|
|
|
} |
|
|
|
|
const char* exception::what() const throw() { |
|
|
|
|
static std::string w; |
|
|
|
|
if (!w.size()) { |
|
|
|
@ -450,7 +455,7 @@ namespace xml { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
Factory::Factory(const Node& t) throw(): _template(t.clone()) {} |
|
|
|
|
Factory::Factory(const Node& t) throw(): _template(t.clone()), _line(0) {} |
|
|
|
|
const Node& Factory::operator*() const throw() { |
|
|
|
|
return *_template; |
|
|
|
|
} |
|
|
|
@ -459,24 +464,32 @@ namespace xml { |
|
|
|
|
second_slash_in_tag, |
|
|
|
|
character_after_slash, missing_end_tag, attribute_value_not_quoted, |
|
|
|
|
access_error, empty_stream, duplicate_attribute, |
|
|
|
|
attributes_in_end_tag) { |
|
|
|
|
attributes_in_end_tag) try { |
|
|
|
|
_line=1; |
|
|
|
|
std::auto_ptr<Node> node(_template->clone()); |
|
|
|
|
node->clear(); |
|
|
|
|
Tag res; |
|
|
|
|
try { |
|
|
|
|
while (true) try { |
|
|
|
|
res = tag(is, *node); |
|
|
|
|
*node<<res.attributes; |
|
|
|
|
switch (res.type) { |
|
|
|
|
case END: throw wrong_end_tag(*node, is, res); |
|
|
|
|
case EMPTY: return node; // empty
|
|
|
|
|
case START: return read(is, *_template); |
|
|
|
|
//! @todo store instead of ignore
|
|
|
|
|
case SPECIAL: break; |
|
|
|
|
} |
|
|
|
|
} catch (missing_end_tag&) { |
|
|
|
|
throw empty_stream(*node, is, res); |
|
|
|
|
} |
|
|
|
|
*node<<res.attributes; |
|
|
|
|
while (true) switch (res.type) { |
|
|
|
|
case END: throw wrong_end_tag(*node, is, res); |
|
|
|
|
case EMPTY: return node; // empty
|
|
|
|
|
case START: return read(is, *_template); |
|
|
|
|
case SPECIAL: break; //! @todo ignored could be stored
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
bool Factory::ws(char c) const throw() { |
|
|
|
|
} catch (exception& e) { |
|
|
|
|
e.line(_line); |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
bool Factory::ws(char c) throw() { |
|
|
|
|
static char last(0); |
|
|
|
|
if ((c=='\n'||c=='\r')&&last!='\n'&&last!='\r') ++_line; |
|
|
|
|
last = c; |
|
|
|
|
return c==' '||c=='\t'||c=='\n'||c=='\r'; |
|
|
|
|
} |
|
|
|
|
std::auto_ptr<Node> Factory::read(std::istream& is, const Node& node) |
|
|
|
@ -516,8 +529,10 @@ namespace xml { |
|
|
|
|
if (!is) throw missing_end_tag(position, is, tag); |
|
|
|
|
if (c!='<') do tag.text+=c; while (is && is.get(c) && c!='<'); |
|
|
|
|
bool nameRead(false); |
|
|
|
|
for (char last(c); is && is.get(c) && c!='>'; last = c) switch (c) { |
|
|
|
|
case ' ': case '\t': case '\n': case '\r': |
|
|
|
|
for (char last(c); is && is.get(c) && c!='>'; last=c) switch (c) { |
|
|
|
|
case '\n': case '\r': |
|
|
|
|
if (last!='\n'&&last!='\r') ++_line; |
|
|
|
|
case ' ': case '\t': |
|
|
|
|
if (!nameRead && tag.name.size()) nameRead=true; |
|
|
|
|
break; |
|
|
|
|
case '/': |
|
|
|
@ -527,14 +542,16 @@ namespace xml { |
|
|
|
|
break; |
|
|
|
|
case '!': case '?': |
|
|
|
|
if (last=='<') { // <! tag or <?xml.. starts
|
|
|
|
|
tag.special+=last; |
|
|
|
|
do tag.special+=c; while (c!='>' && is && is.get(c)); |
|
|
|
|
tag.type=SPECIAL; |
|
|
|
|
return tag; |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
if (tag.type==EMPTY) throw character_after_slash(position, is, tag, c); |
|
|
|
|
if (nameRead) { // read attribute
|
|
|
|
|
std::string attrname(1, c), attrvalue; |
|
|
|
|
while (is && is.get(c) && c!='=' && !ws(c)) attrname+=c; |
|
|
|
|
while (is && is.get(c) && c!='=' && c!='>' && !ws(c)) attrname+=c; |
|
|
|
|
while (c!='=' && is && is.get(c) && ws(c)); // skip ws, search '='
|
|
|
|
|
if (c=='=') { // get the value
|
|
|
|
|
while (is && is.get(c) && ws(c)); // skip ws
|
|
|
|
|