You are on page 1of 22

// XMLDocument.h #ifndef _XMLDocument_h_ #define _XMLDocument_h_ //#define _DEBUG_N_ #include <ctype.

h> #include <string> #include <vector> #include <map> namespace pckxml { typedef std::map<std::string,std::string> str2strMap; typedef std::vector<std::string> stringArray; class XMLElement { private: //fields std::string filename; std::string name; XMLElement* parent; std::vector<XMLElement> childs; std::string value; str2strMap attributes; std::string unparsedContent; std::string unparsedAttributes; bool emptyElement; bool contentParsed; bool attributesParsed; public: //constructors XMLElement(); public: //methods static bool isValidXMLElementChar(char c); static bool isValidXMLElementFirstChar(char c); bool isAttributesParsed(); bool isContentParsed(); void clear();

XMLElement* getRootElement(); void setFile(std::string file); std::string getName(); int getElementsNumber(); XMLElement* getElementPtr(int index); XMLElement* getElementPtr(std::string elemname); bool getElement(int index, XMLElement& element); XMLElement* getElementPtr(stringArray path); XMLElement* getElementPtr(std::vector<int> path); bool getElement(std::string elemname,XMLElement &element); bool getElement(stringArray path,XMLElement &element); bool getElement(std::vector<int> path,XMLElement &element); bool existElement(std::string elemname); /* return index of element */ int getElementIndex(std::string elemname); std::vector<XMLElement> getElements(); str2strMap getAttributes(); bool getAttribute(std::string attName,std::string &attValue); bool isEmpty(); std::string getValue(); /* sets the value of an element */ bool setValue(std::string newvalue); bool getElementValue(std::string element,std::string& evalue); /* adds an empty element */ void addEmptyElement(std::string name,std::string attribs); /* adds an empty element */

void addEmptyElement(std::string name,str2strMap attribs); /* adds an non empty element */ void addElement(std::string name,std::string value,std::string attribs = ""); /* adds an non empty element */ void addElement(std::string name,std::string value,str2strMap attribs); /* adds an element tree */ void addElementTree(std::string name,std::vector<XMLElement> elements, std::string attribs = ""); /* adds an element tree */ void addElementTree(std::string name,std::vector<XMLElement> elements, str2strMap attribs); /* removes an element */ bool removeElement(int index); /* removes an element */ bool removeElement(std::string name); /* write element */ std::string writeElement(); /* Display error messages */ static std::string resolveError(int errorcode,std::string functionName = ""); /* Creates a map of the elements */ str2strMap getElementMap(); /* parse an XML file */ int parseXMLFile(std::string file); /* parsing attributes of caller */ int parseAttributes(); /* parsing elements of caller */ int parseContent(); }; } // namespace pckxml #endif // !define(_XMLdocument_h_) // XMLDocument.cpp #include "XMLDocument.h" #include <fstream>

namespace pckxml { XMLElement::XMLElement() { filename = ""; // only for top level element name = ""; parent = NULL; childs.clear(); value = ""; attributes.clear(); unparsedContent = ""; unparsedAttributes = ""; emptyElement = false; contentParsed = false; attributesParsed = false; } bool XMLElement::isValidXMLElementChar(char c) { return ( isalnum(c) || c == '-' || c == '_' || c == '.'); } bool XMLElement::isValidXMLElementFirstChar(char c) { return (isalpha(c) || c == '_'); } bool XMLElement::isAttributesParsed() { return attributesParsed; } bool XMLElement::isContentParsed() { return contentParsed; } void XMLElement::clear() { filename = ""; name = ""; parent = NULL; childs.clear(); value = ""; attributes.clear(); unparsedContent = ""; unparsedAttributes = ""; emptyElement = false; contentParsed = false;

attributesParsed = false; } XMLElement* XMLElement::getRootElement() { if( parent == NULL ) { return this; } else { return parent->getRootElement(); } } void XMLElement::setFile(std::string file) { getRootElement()->filename = file; } std::string XMLElement::getName() { return name; } int XMLElement::getElementsNumber() { return childs.size(); } XMLElement* XMLElement::getElementPtr(int index) { if( index >= 0 && index < childs.size() ) { return &(childs.at(index)); } return NULL; } XMLElement* XMLElement::getElementPtr(std::string elemname) { for(int ichild = 0; ichild < childs.size(); ichild ++) { if( childs.at(ichild).getName().compare(elemname) == 0) { return &(childs.at(ichild)); } } return NULL;

} bool XMLElement::getElement(int index, XMLElement& element) { if( index >= 0 && index < childs.size() ) { element = childs.at(index); return true; } return false; } XMLElement* XMLElement::getElementPtr(stringArray path) { XMLElement* parentElement = this; XMLElement* newparentElement = NULL; for( int level = 0; level < path.size()-1; level ++) { if( (newparentElement = parentElement->getElementPtr( path.at(level)) ) == NULL ) { return NULL; } parentElement = newparentElement; } if( parentElement != NULL ) { return parentElement->getElementPtr(path.at(path.size()-1)); } return NULL; } XMLElement* XMLElement::getElementPtr(std::vector<int> path) { XMLElement* parentElement = this; XMLElement* newparentElement = NULL; for( int level = 0; level < path.size()-1; level ++) { if( (newparentElement = parentElement->getElementPtr( path.at(level)) ) == NULL ) { return NULL; } parentElement = newparentElement; } if( parentElement != NULL ) { return parentElement->getElementPtr(path.at(path.size()-1)); }

return NULL; } bool XMLElement::getElement(std::string elemname,XMLElement &element) { for(int ichild = 0; ichild < childs.size(); ichild ++) { if( childs.at(ichild).getName().compare(elemname) == 0) { element = childs.at(ichild); return true; } } return false; } bool XMLElement::getElement(stringArray path,XMLElement &element) { XMLElement parentElement = *this; XMLElement newparentElement; for( int level = 0; level < path.size()-1; level ++) { if( ! parentElement.getElement(path.at(level), newparentElement) ) { return false; } parentElement = newparentElement; } return parentElement.getElement(path.at(path.size()-1),element); } bool XMLElement::getElement(std::vector<int> path,XMLElement &element) { XMLElement parentElement = *this; XMLElement newparentElement; for( int level = 0; level < path.size()-1; level ++) { if( ! parentElement.getElement(path.at(level), newparentElement) ) { return false; } parentElement = newparentElement; } return parentElement.getElement(path.at(path.size()-1),element); } bool XMLElement::existElement(std::string elemname) { for(int ichild = 0; ichild < childs.size(); ichild ++)

{ if( childs.at(ichild).getName().compare(elemname) == 0) { return true; } } return false; } int XMLElement::getElementIndex(std::string elemname) { int ichild; for(ichild = 0; ichild < childs.size(); ichild ++) { if( childs.at(ichild).getName().compare(elemname) == 0) { return ichild; } } return -1; } std::vector<XMLElement> XMLElement::getElements() { std::vector<XMLElement> copy; for(int ich = 0; ich < childs.size(); ich ++) { copy.push_back(childs.at(ich)); } return copy; } str2strMap XMLElement::getAttributes() { return attributes; } bool XMLElement::getAttribute(std::string attName,std::string &attValue) { str2strMap::iterator it; if( (it = attributes.find(attName) ) != attributes.end() ) { attValue = it->second; return true; } return false; } bool XMLElement::isEmpty()

{ return emptyElement; } std::string XMLElement::getValue() { return value; } /* sets the value of an element */ bool XMLElement::setValue(std::string newvalue) { if( emptyElement || childs.size() > 0) { return false; } value = newvalue; return true; } bool XMLElement::getElementValue(std::string element,std::string& evalue) { XMLElement* child = getElementPtr(element); if( child == NULL ) { return false; } evalue = child->value; return true; } /* adds an empty element */ void XMLElement::addEmptyElement(std::string name,std::string attribs) { XMLElement child; child.parent = this; child.name = name; child.unparsedAttributes = attribs; child.emptyElement = true; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = false; child.parseAttributes(); childs.push_back(child); } /* adds an empty element */ void XMLElement::addEmptyElement(std::string name,str2strMap attribs)

{ XMLElement child; child.parent = this; child.name = name; child.unparsedAttributes = ""; child.emptyElement = true; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = true; child.attributes = attribs; childs.push_back(child); } /* adds an non empty element */ void XMLElement::addElement(std::string name,std::string value,std::string attribs) { XMLElement child; child.parent = this; child.name = name; child.value = value; child.unparsedAttributes = attribs; child.emptyElement = false; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = false; child.parseAttributes(); childs.push_back(child); } /* adds an non empty element */ void XMLElement::addElement(std::string name,std::string value,str2strMap attribs) { XMLElement child; child.parent = this; child.name = name; child.value = value; child.unparsedAttributes = ""; child.emptyElement = false; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = true; child.attributes = attribs; childs.push_back(child); } /* adds an element tree */ void XMLElement::addElementTree(std::string name,std::vector<XMLElement> elements, std::string attribs) {

XMLElement child; child.parent = this; child.name = name; for( int ich = 0; ich < elements.size(); ich ++) { child.childs.push_back(elements.at(ich)); } child.unparsedAttributes = attribs; child.emptyElement = false; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = false; child.parseAttributes(); childs.push_back(child); } /* adds an element tree */ void XMLElement::addElementTree(std::string name,std::vector<XMLElement> elements, str2strMap attribs) { XMLElement child; child.parent = this; child.name = name; for( int ich = 0; ich < elements.size(); ich ++) { child.childs.push_back(elements.at(ich)); } child.unparsedAttributes = ""; child.attributes = attribs; child.emptyElement = false; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = true; childs.push_back(child); } /* removes an element */ bool XMLElement::removeElement(int index) { if( index < 0 || index >= childs.size() ) { return false; } std::vector<XMLElement>::iterator it; int count; for(it = childs.begin(),count = 0; count < index; count ++) { it ++; }

childs.erase(it); return true; } /* removes an element */ bool XMLElement::removeElement(std::string name) { int index = getElementIndex(name); if( index == -1 ) { return false; } return removeElement(index); } /* write element */ std::string XMLElement::writeElement() { std::string elementStr; if( parent == NULL ) { elementStr ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<"; } else { elementStr = "<"; } elementStr.append(name); // attributes str2strMap::iterator it; for( it = attributes.begin(); it != attributes.end(); it ++) { elementStr.append(" ").append(it->first).append("=\"").append(it->second).append("\""); } // childs if( emptyElement ) { elementStr.append(" />\r"); } else { elementStr.append(">\r\t"); if( childs.size() > 0) { for( int ichild = 0; ichild < childs.size()-1; ichild ++) {

elementStr.append( childs.at(ichild).writeElement() ).append("\r\t"); } elementStr.append( childs.at(childs.size()-1).writeElement() ).append("\r"); } elementStr.append("\t").append(value).append("\r"); elementStr.append("</").append(name).append(">\r"); } return elementStr; } /* Creates a map of the elements */ str2strMap XMLElement::getElementMap() { str2strMap elementMap; if( childs.size() > 0 ) { for(int ichild = 0; ichild < childs.size(); ichild ++) { str2strMap childMap = childs.at(ichild).getElementMap(); str2strMap::iterator it; std::string basename; for( it = childMap.begin(); it != childMap.end(); it ++) { basename = name; basename.append(":").append(it->first); elementMap.insert(str2strMap::value_type(basename, it->second)); } } } else { elementMap.insert(str2strMap::value_type(name,value)); } return elementMap; } /* Display error messages */ std::string XMLElement::resolveError(int errorcode,std::string functionName) { std::string comment; switch( errorcode ) { case -65535: case -65534: case -65533: case -65532: comment = "method fatal error"; break;

case 0: comment = "no error"; break; case -1: comment = "error opening file"; break; case -2: comment = "error closing file"; break; case -3: comment = "malformed document: not closing tag -->"; break; case -4: comment = "malformed document: missing header"; break; case -5: comment = "malformed document: not closing header tag (?>)"; break; case -6: comment = "malformed document: multiple headers in the document"; break; case -7: comment = "malformed document: no top level element found"; break; case -8: comment = "malformed document: invalid character in element or property name"; break; case -9: comment = "malformed document not closing tag (>)"; break; case -10: comment = "malformed document: closing element tag not found"; break; case -11: comment = "malformed document: malformed attribute - value pair"; break; case -12: comment = "malformed document: invalid character format for attribute (missing equal sign)"; break; case -13: comment = "malformed document: invalid character found while searching for attribute"; break; case -14: comment = "malformed document: value not found for attribute"; break; case -15: comment = "malformed document: closing double quote not found"; break; case -16:

comment = "malformed document: closing quote not found"; break; default: comment = "unknown error"; break; }; char crlf[2],TAB_CHAR[1],numd[8],numh[8]; sprintf(crlf,"%c%c",0x0d,0x0a); sprintf(TAB_CHAR,"%c",0x09); sprintf(numh,"%08x",errorcode); sprintf(numd,"%d",errorcode); std::string str = crlf; str = (((((((((str.append("") ).append(functionName )).append(crlf)).append(TAB_CHAR)).append("Error: 0x")).append(numh)).append(" (") ).append(numd)).append(") ")).append( comment); return str; } int XMLElement::parseXMLFile(std::string fname) { clear(); std::ifstream filein; filein.open(fname.data()); if( !filein.is_open() ) { return -1; // error opening file } filename = fname; std::string fileContent; char ch; while( !filein.eof() ) { filein.get(ch); fileContent += ch; } filein.close(); if( filein.is_open() ) { return -2; // error closing file } //remove all comments size_t startpos = std::string::npos; size_t endpos = std::string::npos;

do { startpos = fileContent.find("<!--"); if( startpos != std::string::npos ) { endpos = fileContent.find("-->",startpos); if( endpos == std::string::npos ) { return -3; // malformed document: not closing tag --> } fileContent = fileContent.erase(startpos,endpos+3-startpos); } } while( startpos != std::string::npos && endpos != std::string::npos ); // remove header startpos = fileContent.find("<?xml"); if( startpos == std::string::npos ) { return -4; // malformed document: missing header } endpos = fileContent.find("?>",startpos); if( endpos == std::string::npos ) { return -5; // malformed document: not closing header tag (?>) } fileContent = fileContent.erase(startpos,endpos+2-startpos); // check for second header startpos = fileContent.find("<?"); if( startpos != std::string::npos ) { return -6; // malformed document: multiple headers in the document } // find top level element if( (startpos = fileContent.find("<") ) == std::string::npos) { return -7; // malformed document: no element found } endpos = startpos+1; if( ! isValidXMLElementFirstChar(fileContent.at(endpos))) { return -8; // malformed document: invalid character in element or property name } while( isValidXMLElementChar(fileContent.at(++endpos) ))

{} size_t endTagpos = std::string::npos; if((endTagpos = fileContent.find(">",startpos)) == std::string::npos) { return -9; // malformed document not closing tag (>) } std::string element = fileContent.substr(startpos+1,endpos-startpos-1); std::string search = "</"; search += element; size_t startpos1 = std::string ::npos, endpos1 = std::string::npos; if( (startpos1 = fileContent.find(search,endTagpos) ) == std::string::npos) { return -10; // malformed document: closing element tag not found } if((endpos1 = fileContent.find(">",startpos1) ) == std::string::npos) { return -9; // malformed document not closing tag (>) } name = element; unparsedAttributes = fileContent.substr( endpos, endTagpos-endpos); unparsedContent = fileContent.substr(endTagpos+1,startpos1-endTagpos-1); fileContent = ""; int result = parseAttributes(); if( result != 0) { return result; } result = parseContent(); if( result != 0) { return result; } return result; } // parsing attributes of caller int XMLElement::parseAttributes() { if( attributesParsed ) { return 0;

} size_t startpos = 0; size_t endpos = std::string::npos; size_t startpos1 = std::string::npos; size_t endpos1 = std::string::npos; size_t currentpos = std::string::npos; size_t esignpos = std::string::npos; // identify attributes do { if( unparsedAttributes.empty() ) { attributesParsed = true; break; // no attributes } bool empty = true; for(currentpos = startpos; currentpos < unparsedAttributes.length() && empty; currentpos ++) { empty = empty && isspace(unparsedAttributes.at(currentpos)); } if( empty ) { attributesParsed = true; break; } while(isspace(unparsedAttributes.at(startpos) ) ) { startpos ++; } if( !isValidXMLElementFirstChar(unparsedAttributes.at(startpos)) ) { clear(); return -8; // malformed document: invalid character in element or property name } for(endpos = startpos+1; endpos < unparsedAttributes.length() && isValidXMLElementChar(unparsedAttributes.at(endpos)); endpos ++) {} if( (esignpos = unparsedAttributes.find("=")) == std::string::npos) { clear();

return -12; // malformed document: invalid format for attribute (missing equal sign) } for(currentpos = endpos; currentpos < esignpos; currentpos ++) { if( !isspace(unparsedAttributes.at(currentpos)) ) { clear(); return -13; // malformed document: invalid character found while searching for attribute } } if((startpos1 =unparsedAttributes.find_first_of("\"\'") ) == std::string::npos) { clear(); return -14; // malformed document: value not found for attribute } if( unparsedAttributes.at(startpos1) == '\"' ) { if((endpos1 = unparsedAttributes.find("\"",startpos1+1)) == std::string::npos) { clear(); return -15; // malformed document: closing double quote not found } } else if ( unparsedAttributes.at(startpos1) == '\'') { if((endpos1 = unparsedAttributes.find("\'",startpos1+1)) == std::string::npos) { clear(); return -16; // malformed document: closing quote not found } } else { clear(); return -65535; // method fatal error } attributes.insert(str2strMap::value_type( unparsedAttributes.substr(startpos,endpos-startpos), unparsedAttributes.substr(startpos1+1,endpos1-startpos1-1) ) ); unparsedAttributes = unparsedAttributes.erase(startpos,endpos1+1-startpos); } while( ! attributesParsed );

return 0; } // parsing elements of caller int XMLElement::parseContent() { if( contentParsed ) { int result = 0; return result; } size_t startpos = std::string::npos; size_t endpos = std::string::npos; size_t endTagpos = std::string::npos; // start processing do { if( (startpos = unparsedContent.find("<") ) == std::string::npos) { value = unparsedContent; unparsedContent = ""; return 0; // no element found } if(!isValidXMLElementFirstChar(unparsedContent.at(startpos+1))) { return -8; // invalid character } // find end of tag if( (endTagpos = unparsedContent.find(">",startpos)) == std::string::npos) { return -9; // no closing tag } endpos = startpos+1; while( endpos < endTagpos && isValidXMLElementChar( unparsedContent.at(endpos) ) ) { endpos ++; } if( unparsedContent.at(endTagpos-1) != '/') { // not empty element std::string search = "</"; search += unparsedContent.substr(startpos+1,endpos-startpos-1);

; size_t startpos1 = std::string::npos; size_t endpos1 = std::string::npos; if( (startpos1 = unparsedContent.find(search,endTagpos)) == std::string::npos) { return -10; // no closing element tag } if( (endpos1 = unparsedContent.find(">",startpos1)) == std::string::npos) { return -9; // no closing > } XMLElement child; child.parent = this; child.name = unparsedContent.substr(startpos+1, endpos-startpos-1); child.unparsedAttributes = unparsedContent.substr(endpos, endTagpos-endpos); child.emptyElement = false; child.unparsedContent = unparsedContent.substr(endTagpos+1,startpos1-endTagpos-1); child.contentParsed = false; child.attributesParsed = false; child.parseAttributes(); child.parseContent(); childs.push_back(child); // remove processed part of content unparsedContent = unparsedContent.erase(startpos, endpos1+1-startpos); } else { // empty element // correct value of endTagpos to point to /> endTagpos --; XMLElement child; child.parent = this; child.name = unparsedContent.substr(startpos+1,endpos-startpos-1); child.unparsedAttributes = unparsedContent.substr(endpos,endTagpos-endpos); child.emptyElement = true; child.unparsedContent = ""; child.contentParsed = true; child.attributesParsed = false; child.parseAttributes(); childs.push_back(child); // remove processed part of content

unparsedContent = unparsedContent.erase(startpos,endTagpos+2-startpos); } if( unparsedContent.empty() ) { contentParsed = true; } else { bool empty = true; for( startpos = 0; startpos < unparsedContent.length() && empty; startpos ++ ) { empty = empty && isspace(unparsedContent.at(startpos)); } contentParsed = empty; } } while(! contentParsed); // end processing return 0; } } // namespace pckxml