#include <iostream>#include <list>#include <fstream>#include <map>#include <cctype>#include <sstream>namespace xml{ class contents { public: bool is_element; std::string text; contents() { is_element = false; } contents(std::string &text) { this->text = text; } }; class tag { public: std::string name; std::map<std::string, std::string> attributes; void clear() { name.clear(); attributes.clear(); } }; static wchar_t *entity_table[] = { L"amp", // & L"lt", // < L"gt" // > L"apos", // ' L"quot" // " }; static wchar_t translated_table[] = { L'&', // amp L'<', // lt L'>', // gt L'\'', // ' L'"' // " }; class element : public tag, public contents { public: std::list<contents*> sections; element *parent; element() { parent = 0; is_element = true; } ~element() { for(std::list<contents*>::iterator i=sections.begin(); i != sections.end(); ++i) { delete (*i); } } element(tag &t) { element(); name = t.name; attributes = t.attributes; } element(std::istream &s) { element(); load(s); } // Note: Could check if after the file is loaded that open_element == this. // This would indicate that most likely everything went OK. void load(std::istream &s) { parent = 0; element *open_element = this; text.clear(); attributes.clear(); sections.clear(); tag buf_tag; // Tag buffer. std::string buf_gen; // Generic string buffer. Used for attribute values, and plain text contents. std::string buf_ent; // Character entity buffer. std::string buf_attr; // Attribute name buffer. int open_tags = 0; // A counter for open tags to establish blocks. unsigned int cur = 0; // Bit field with any of the following flags... static const unsigned int cur_intag = 0x1; // Currently processing a tag. static const unsigned int cur_foundroot = 0x2; // We found at least the root element. static const unsigned int cur_ent = 0x4; // Currently processing a character entity. static const unsigned int cur_attr = 0x8; // Currently processing an attribute. static const unsigned int cur_str = 0x10; // Currently processing an attribute value within quotes. static const unsigned int cur_pastname = 0x20; // The tag name was already found. static const unsigned int cur_closing = 0x40; // We found a forward slash in the tag. static const unsigned int cur_opening = 0x80; // The forward slash was not before the tag name. static const unsigned int cur_declaration = 0x100; // We are in the initial XML declaration I.E: <?xml version="1.0"?>. // while(open_tags || !(cur & cur_foundroot)) // Continue until we have found and closed the root element. for(;;) { int c = s.get(); // Fetch next character from stream. if(c == EOF) break; if(!(cur & cur_str)) // If we are not in a string. { // Conclusion: Tag syntactic stuff is OK. if(c == '<') // Start tag {// open_element->text = buf_gen; if(buf_gen.size()) // If we found some plain text. { // Add plain text contents to "sections" list. open_element->sections.push_back(new contents(buf_gen)); buf_gen.clear(); } cur |= cur_intag; // Set in-tag flag. cur |= cur_opening; // Set tag-is-opening flag. // This will be removed if a forward slash is found before the tag name. continue; // Already identified the character. } if(c == '>') // End tag { if(cur & cur_closing) // If we found a slash before the tag name. { // Conclusion: This is a closing tag. open_element->text = buf_gen; open_element = open_element->parent; // Step back up to parent element.// open_tags--; // One step closer to closing the root element. } else { // Conclusion: This is an opening tag for a new child element. if(cur & cur_foundroot) { element *tmp = open_element; // Save open element open_element = new element(buf_tag); open_element->parent = tmp; // Set new child's parent tmp->sections.push_back(open_element); } else { *this = buf_tag; cur |= cur_foundroot; // Set found-root-element flag. }// open_element->text.clear();/* if(tmp_text.size()) // If we have accumulated any text before this tag { // Add it as a contents contents *tmp = open_element; // Save open element contents *ns = new contents; ns->text = tmp_text; open_element->sections.push_back(ns); tmp_text.clear(); }*/// open_tags++; // One step further from closing the root element. } // Clear flags used in tag, and tag name buffer. cur &= ~cur_pastname; cur &= ~cur_intag; cur &= ~cur_closing; buf_tag.clear(); continue; // Already identified the character. } if(c == '/') // If this character is a forward slash. { if(cur & cur_intag) // If we're in a tag. { cur |= cur_closing; // Set tag-is-closing flag. if(buf_tag.name.empty()) // If we haven't gotten the tag name yet. { // Conclusion: This is ONLY a closing tag. cur &= ~cur_opening; // Clear tag-is-opening flag. } } continue; } if(c == '=') // If this character is an equal sign. { if(cur & cur_intag) // If inside a tag. { // Conclusion: This must be an attribute assignment operator. cur |= cur_attr; // Set currently-assigning-attribute flag. } continue; // Already identified the character. } } if(c == '"') // If this character is a quote mark. { if(cur & cur_intag) // If inside a tag. { if(cur & cur_attr) // If currently assigning an attribute. { if(cur & cur_str) // If already reading in a string. { // Conclusion: This is a closing quote mark for an attribute value. buf_tag.attributes[buf_attr] = buf_gen; buf_gen.clear(); buf_attr.clear(); cur &= ~cur_str; // Clear currently-reading-string flag. cur &= ~cur_attr; // Clear currently-assigning-attribute flag. } else { cur |= cur_str; // Set the currently-reading-string flag. } } } continue; // Already identified the character. } if(c == '&') // Start an entity { cur |= cur_ent; continue; // Already identified the character. } if(c == ';') // End an entity { cur &= ~cur_ent;/* for(int i=0; i < sizeof(entity_table); ++i) { //if( wcscmp(entity_table[i], buf_ent.c_str()) ) { // buf_gen += translated_table[i]; } }*/ continue; // Already identified the character. } // What to expect inside a tag changes with whitespace. if(std::isspace(c)) // If this character is whitespace. { if(cur & cur_intag) // If inside a tag { if(buf_tag.name.size()) // If tag name buffer is not empty. { // Conclusion: We are past the tag name and now reading attributes. cur |= cur_pastname; // Set currently-past-name flag. } } continue; // Already identified the character. } // No syntactic matches... if(cur & cur_intag) // If inside a tag. { if(cur & cur_pastname) // If past the tag name { // Conclusion: Reading in attributes. if(cur & cur_str) // If inside a string. { // Conclusion: Setting an attribute value. if(cur & cur_ent) // If inside an entity { buf_ent += c; // Append this character to the entity buffer for conversion. } else { buf_gen += c; // Append this character directly to the attribute value buffer. } } else { // Conclusion: Reading an attribute name, not a value. buf_attr += c; // Append this character to the attribute name buffer. } } else { // Conclusion: We are still reading in the tag name. buf_tag.name += c; // Append character to temporary tag name buffer. } } else // Not inside a tag { // Conclusion: Plain text contents. buf_gen += c; // Append this character to the generic text buffer. } } // for(;;) } }; class file : element { public: file(std::string filename) { } };}void print_tabs(int indent){ while(indent) { std::cout << '\t'; indent--; }}void print_elem(xml::element *elem, int indent=0){ for(std::list<xml::contents*>::iterator i=elem->sections.begin(); i != elem->sections.end(); ++i) { print_tabs(indent); std::cout << "section: " << (*i)->text << std::endl; if((*i)->is_element) { xml::element *ass = (xml::element*)&*(*i); print_elem(ass, indent+1); } }}int main(){ xml::element poop( std::ifstream("test.xml") ); print_elem(&poop); system("pause"); return 0;}