A while back, I posted an XML Writer. Today I have finished what I hope to be a solid XML parser that, while not professional, will get the job done.To start, I do use a stack on one part of the parser, so you can find the code for that in the XML writer page I linked above.Xml.h#ifndef Xml_H#define Xml_H#include <fstream>#include <iostream>#include LinkStack.h#include <string>#include <vector>#include <windows> //Error reporting with message boxes. namespace Xml {    enum class ErrorCode {        None,        StreamError,        FileExistError,        ElementCloseError,        ElementTagsNotEmpty    };    class Error {    public:        /**           Constructor        */        Error();        /**            Throws Error Message and displays the message in messagebox        */        void ThrowError(ErrorCode errorCode);    private:        ErrorCode err;        const char* errMsg;    };    Error::Error() :        err(ErrorCode::None),        errMsg(nullptr)    {    }    void Error::ThrowError(ErrorCode errorCode) {        err = errorCode;        if (errorCode != ErrorCode::None) {            switch (errorCode) {            case ErrorCode::StreamError:                errMsg = Stream error has occured;                break;            case ErrorCode::FileExistError:                errMsg = File does not exist;                break;            case ErrorCode::ElementCloseError:                errMsg = No elements to close;                break;            case ErrorCode::ElementTagsNotEmpty:                errMsg = Not all element tags are closed. Closing remaining tags;                break;            }            MessageBox(NULL, errMsg, Error Has Occured, MB_ICONEXCLAMATION | MB_OK);        }        errMsg = nullptr;    }    class XmlReader : private Error {    public:        /**            Child Node        */        struct cNode {            std::vector<cNode> childNode;            std::string strInnerText;            std::vector<std::string> strAttributeName;            std::vector<std::string> strAttributeValue;            bool hasChildNode();        };        /**            Parent Node        */        struct pNode {            std::vector<cNode> childNode;            std::string strInnerText;            std::vector<std::string> strAttributeName;            std::vector<std::string> strAttributeValue;            bool hasChildNode();        };        /**            Structure of parent and child nodes        */        struct node {            std::vector<pNode> parentNode;            std::string strInnerText;            std::vector<std::string> strAttributeName;            std::vector<std::string> strAttributeValue;        };        /**            Constructor        */        XmlReader();        /**            Loads the file        */        bool load(std::string strFileName);        /**            Closed the file        */        void close();        /*            Gets Node by Tag Name        */        XmlReader::node getElementByTagName(std::string strTagName);    private:        /**            Checks if the file exists        */        bool exists(std::string strFileName);        /**            Checks if the file is open        */        bool isOpen();        /**            Gets child nodes        */        XmlReader::cNode getChildNodes();        /**            Gets Attributes        */        void getAttributes(std::string& strOpenTag, std::string& strAttName, std::string& strAttValue);        /*            Get Inner Text        */        void getInnerText(std::string& strInLine, std::string& strInnerText);        std::ifstream& goToLine(std::ifstream& file, int lineNUm);        std::ifstream   m_ifsInFile;        std::string     m_strParentNode;        std::size_t     m_nLineNum;        bool            m_bDocOpen;        LinkStack<std::string> m_lsstrChildNodeName;    };    XmlReader::XmlReader() {        m_bDocOpen = false;        m_strParentNode = ;        m_nLineNum = 0;    }    bool XmlReader::load(std::string strFileName) {        if (!exists(strFileName)) {            Error::ThrowError(ErrorCode::FileExistError);            return false;        }        else {            m_ifsInFile.open(strFileName, std::ios::in);        }        m_bDocOpen = isOpen();        if (!m_bDocOpen) {            Error::ThrowError(ErrorCode::StreamError);            return false;        }        return true;    }    void XmlReader::close() {        m_ifsInFile.close();    }    bool XmlReader::exists(std::string strFileName) {        std::ifstream ifsCheckFile(strFileName);        return !!ifsCheckFile;    }    bool XmlReader::isOpen() {        if (!m_ifsInFile.is_open()) {            return false;        }        return true;    }    XmlReader::node XmlReader::getElementByTagName(std::string strTagName) {        XmlReader::node node;        XmlReader::pNode parentNode;        XmlReader::cNode childNode;        std::string strInnerText;        std::string strAttributeName;        std::string strAttributeValue;        std::size_t sz = strTagName.size();        std::string strInLine;        std::string strTmp;        std::string strOpenTag;        int posLt = 0;        int posGt = 0;        int posFAtr = 0;        int posLAtr = 0;        int posLastAtr = 0;        m_strParentNode = strTagName;        while (std::getline(m_ifsInFile, strInLine, '\n')) {            parentNode.strAttributeName._Pop_back_n(parentNode.strAttributeName.size());            parentNode.strAttributeValue._Pop_back_n(parentNode.strAttributeValue.size());            m_nLineNum = m_ifsInFile.tellg();            if (strInLine != ) {                if (strInLine[0] == '\t') {                    std::vector<int> tabPos;                    for (int i = 0; i < strInLine.size(); i++) {                        if (strInLine[i] == '\t') {                            tabPos.push_back(i);                        }                    }                    for (int i = tabPos.size(); i > 0; i--) {                        strInLine.erase(tabPos[i - 1], 1);                        tabPos.pop_back();                    }                }                if (strInLine.substr(1, sz) == strTagName) {                    posLt = strInLine.find_last_of(<);                    posGt = strInLine.find_last_of(>);                    strTmp = strInLine.substr(posLt + 1, posGt - posLt - 1);                    if (strTmp == / + strTagName) {                        posLt = strInLine.find_first_of(<);                        posGt = strInLine.find_first_of(>);                        strOpenTag = strInLine.substr(posLt + 1, posGt - posLt - 1);                        if (strOpenTag.size() > sz) {                            while (strOpenTag.size() > sz) {                                getAttributes(strOpenTag, strAttributeName, strAttributeValue);                                parentNode.strAttributeName.push_back(strAttributeName);                                parentNode.strAttributeValue.push_back(strAttributeValue);                            }                        }                        getInnerText(strInLine, strInnerText);                        parentNode.strInnerText = strInnerText;                    }                    else {                        childNode = getChildNodes();                        parentNode.childNode.push_back(childNode);                    }                    node.parentNode.push_back(parentNode);                }            }        }        return node;    }    XmlReader::cNode XmlReader::getChildNodes() {        XmlReader::cNode tmpNode;        XmlReader::cNode childNode;        std::string strInLine;        std::string strInnerText;        std::string strAttributeName;        std::string strAttributeValue;        std::string strTagName;        std::string strEndTag;        std::string strOpenTag;        std::size_t sz;        int posF = 0;        int posL = 0;        int posS = 0;        int posLt = 0;        int posGt = 0;        bool endTag = false;        if (m_nLineNum != m_ifsInFile.tellg()) {            goToLine(m_ifsInFile, m_nLineNum);        }        while (!endTag) {            std::getline(m_ifsInFile, strInLine, '\n');            m_nLineNum = m_ifsInFile.tellg();            if (strInLine != ) {                posF = strInLine.find_first_of(<);                posL = strInLine.find_first_of(>);                posS = strInLine.find_first_of( );                if (posS < posL && posS > posF) {                    strTagName = strInLine.substr(posF + 1, posS - posF - 1);                }                else {                    strTagName = strInLine.substr(posF + 1, posL - posF - 1);                }                if (strTagName.substr(0, 1) == /) {                    strTagName.erase(0, 1);                }                m_lsstrChildNodeName.push(strTagName);                posF = strInLine.find_last_of(<);                posL = strInLine.find_last_of(>);                if (strInLine.substr(posF + 1, posL - posF - 1) != / + m_lsstrChildNodeName.top()) {                    childNode.strAttributeName._Pop_back_n(childNode.strAttributeName.size());                    childNode.strAttributeValue._Pop_back_n(childNode.strAttributeValue.size());                    sz = strTagName.size();                    if (strInLine.substr(1, sz) == strTagName) {                        posLt = strInLine.find_first_of(<);                        posGt = strInLine.find_first_of(>);                        strOpenTag = strInLine.substr(posLt + 1, posGt - posLt - 1);                        if (strOpenTag.size() > sz) {                            while (strOpenTag.size() > sz) {                                getAttributes(strOpenTag, strAttributeName, strAttributeValue);                                childNode.strAttributeName.push_back(strAttributeName);                                childNode.strAttributeValue.push_back(strAttributeValue);                            }                        }                        posLt = strInLine.find_last_of(<);                        posGt = strInLine.find_last_of(>);                        strEndTag = strInLine.substr(posLt + 1, posGt - posLt - 1);                        if (strEndTag == / + strTagName) {                            getInnerText(strInLine, strInnerText);                            childNode.strInnerText = strInnerText;                        } else {                            tmpNode = getChildNodes();                            childNode.childNode.push_back(tmpNode);                        }                    } else {                        m_lsstrChildNodeName.pop();                        endTag = true;                    }                } else {                    getInnerText(strInLine, strInnerText);                    childNode.strInnerText = strInnerText;                    m_lsstrChildNodeName.pop();                    endTag = true;                }            }        }        return childNode;    }    void XmlReader::getAttributes(std::string& strOpenTag, std::string& strAttName, std::string& strAttValue) {        int posF = 0;        int posL = 0;        posF = strOpenTag.find_first_of( );        posL = strOpenTag.find_first_of(=);        strAttName = strOpenTag.substr(posF + 1, posL - posF - 1);        strOpenTag.erase(posF, posL - posF + 1);        posF = strOpenTag.find_first_of(\);        posL = posF;        posF = strOpenTag.find(\, posF + 1);        strAttValue = strOpenTag.substr(posL + 1, posF - posL - 1);        strOpenTag.erase(posL, posF - posL + 1);    }    void XmlReader::getInnerText(std::string& strInLine, std::string& strInnerText) {        int posLt = 0;        int posGt = 0;        posLt = strInLine.find_last_of(<);        posGt = strInLine.find_first_of(>);        strInnerText = strInLine.substr(posGt + 1, posLt - posGt - 1);    }    std::ifstream& XmlReader::goToLine(std::ifstream& file, int lineNum) {        file.seekg(std::ios::beg);        file.seekg(lineNum);        return file;    }    bool XmlReader::pNode::hasChildNode() {        if (XmlReader::pNode::childNode.size() != 0) {            return true;        }        return false;    }    bool XmlReader::cNode::hasChildNode() {        if (XmlReader::cNode::childNode.size() != 0) {            return true;        }        return false;    }}#endifmain.cpp#include Xml.hint main() {    Xml::XmlReader xmlR;    if (xmlR.load(path\\to\\xml\\doc)) {        Xml::XmlReader::node xmlNode;        xmlNode = xmlR.getElementByTagName(TagName);        std::cout << xmlNode.parentNode[0].//enter rest of statement to get child nodes,                                           //attributes, or what ever that is collected.    }}I hope this is legible. I'm here to learn, so lay it on me.
Basic XML Parser
c++;parsing;xml
Relying on specific type of error message deep inside your library makes it very tied to a specific platform.void Error::ThrowError(ErrorCode errorCode) {       // STUFF        MessageBox(NULL, errMsg, Error Has Occured, MB_ICONEXCLAMATION | MB_OK);       // STUFF}Your library should not be handling user interactions. This is the job of the application. The library should just inform the application that an error has occurred and then let the application decide what to do (this code could be used in some background server app; you defiantly do not want a dialog box to show up on a headless server).Two big options.Throw an exception.Allow the user to specify a callback that is called on error.Or both. The default action of the callback (if not provide by the user) is to throw.Do you really need a cNode, pNode and Node? They all look identical.Comments like this:    /**        Checks if the file exists    */    bool exists(std::string strFileName);    /**        Checks if the file is open    */    bool isOpen();are a waste of space. They are not part of the public interface and the function name clearly identifies what they do. Useless comments are worse than no comments as they need to be maintained.The check for file existence seems overly hyperbolic:    if (!exists(strFileName)) {        Error::ThrowError(ErrorCode::FileExistError);        return false;    }    else {        m_ifsInFile.open(strFileName, std::ios::in);    }The call to exist merely tries to create a file stream object and returns its state. Why not just try and open the file then check its state.    m_ifsInFile.open(strFileName, std::ios::in);    if (!m_ifsInFile) {        Error::ThrowError(ErrorCode::FileExistError);        return false;    }Double negative check.   return !!ifsCheckFile;That's old school not seen that in a while. But its also not even needed. A stream object used in a boolean context (like returning a bool from a function) is converted to a boolean value (or pre C++11 a value that can be used in a boolean context).So easier to write:   return ifsCheckFile;  // And much easier to understand for those that have not                         // seen the double negative check trick.Don't use if to check the state of a boolen    if (!m_ifsInFile.is_open()) {        return false;    }    return true;    // much easier to write as:    return m_ifsInFile.is_open();