Click here to Skip to main content
15,881,588 members
Articles / Programming Languages / C++11

XML++ version 3: The C++11 Update of My XML Library

Rate me:
Please Sign up or sign in to vote.
4.90/5 (34 votes)
3 Sep 2018CPOL2 min read 79.6K   1.5K   66   16
The update to my beloved library. Single-header file.

Introduction

The C++11 version of my popular XML Library (http://www.codeproject.com/Articles/18732/XML-Include-a-Flexible-Parser-in-Your-C-Applicatio) with a cleaner interface, within one .h file which can be used in precompiled headers as well.

BXML

A class to represent binary data in XML. Can set/get from Base64.

C++
// BXML
class BXML
    {
    private:
        vector<char> d;
    public:
    
        BXML(size_t s = 0);
        bool operator ==(const BXML& b2);

        void ToB(string& s);
        void FromB(const char* ba);
        operator const char*() const;
        operator char*();
        const char* p() const;
        char* p();
        size_t size() const;

        void clear();
        void reset();

        void Ensure(size_t news);
        void Resize(size_t news);
        void AddResize(size_t More);
    };

XMLContent

  • Constructor can initialize from:
    • Value:
      C++
      XMLContent v("n");
    • Another Variable:
      C++
      XMLContent v2 = v;
  • Enhancements
    • Set value:
      C++
      v2 = "hello";
    • Binary contents:
      C++
      v2.SetBinaryData("\0\0\0",3);
    • operator const char*():
      C++
      string z = v2;
  • Templates to set and get:
    • v3.SetFormattedValue<int>("%d",5);
    • v3.SetFormattedValue<const char*>("%s","hello");
    • auto j = v3.GetFormattedValue<int>("%d"); // using sscanf, j = int.
  • Serialization to string with or without encoding.
    C++
    class XMLContent
        {
        protected:
            string v;
            size_t ep = 0;
    
        public:
    
            XMLContent();
            XMLContent(size_t ElementPosition,const char* ht);
            XMLContent(size_t ElementPosition,const wchar_t* ht);
    
            size_t MemoryUsage();
    
            // Operators
            bool operator==(const XMLContent& t) const;
            operator const string& () const;
    
            // Sets
            const string& SetFormattedValue(const char* fmt,...);
            template <typename T> const string& SetFormattedValue(const char* fmt,T ty)
                {
                unique_ptr<char> t(new char[10000]);
                sprintf_s(t.get(),fmt,10000,ty);
                SetValue(t);
                return v;
                }
    
            XMLContent&  operator =(const char* s);
            XMLContent&  operator =(const string& s);
            const string& SetBinaryValue(const char* data,size_t len);
    
            void SetValue(const char* VV);
            void SetValue(const string& VV);
            void Clear();
            void SetEP(size_t epp);
    
            // Gets
            BXML GetBinaryValue() const;
            template <typename T> T GetFormattedValue(const char* fmt) const
                {
                T x;
                sscanf(v.c_str(),fmt,&x);
                return x;
                }
    
            const string& GetValue() const;
            size_t GetEP() const;
    
            // Serialization
            virtual string Serialize(bool NoEnc = false) const;
    
        };

XMLComment, XMLCData, XMLDocType and XMLVariable/XMLAttribute

All these inherit from XMLContent. In addition, XMLVariable includes methods to set/get the attribute name. With the same functions, all these classes can now, for example, set binary values for their contents.

C++
class XMLVariable : public XMLContent
    {
    private:
        string n;
        bool tmp = false;
    public:

        explicit XMLVariable();
        explicit XMLVariable(const char* nn,const char* vv,bool Temp = false);
        explicit XMLVariable::XMLVariable(const XMLVariable& h);
        XMLVariable& operator =(const XMLVariable& h);
    //    XMLVariable& operator =(const std::initializer_list<string>& s); 

        const string& SetName(const char* VN);
        const string& SetName(const string& VN);
        void Clear();
        XMLVariable&  operator =(const char* s);
        XMLVariable&  operator =(const string& s);

        // Compare 
        bool operator <(const XMLVariable& x) const;
        bool operator ==(const XMLVariable& x) const;
        bool operator ==(const char* x) const;
        // Gets
        const string& XMLVariable::GetName() const;

        // Memory usage
        size_t MemoryUsage() const;

        
        // Serialization
        virtual string Serialize(bool NoEnc = false) const;
    };

XMLHeader

The XML header class contains the standalone, version and encoding as attributes, so you can access them via XMLVariable.

XMLElement

XMLElement features:

  • shared_ptr arrays of all child elements, contents, comments, cdatas, attributes.
    C++
    vector<shared_ptr<XMLElement>> v = el.GetChildren();
  • Access to elements via operator [] and an index:
    C++
    el[0].vv["animal"] = "rabbit";
  • Access via operator [] and a string, creates children if they do not exist:
    C++
    el["hello"]["there"] = "<there v=\"test\">";
  • Access to attributes via v() with index or variable name, or with vv() for the full XMLVariable:
    C++
    string g = el.v("t");
  • Copy or mirror:
    C++
    XMLElement e1 = "<e v=\"hi\">";
    	XMLElement e2 = e1;
    	XMLElement e3 = e1.Mirror();
    	e1.vv("v") = "hello"; // e3 variable is changed as well, e2 still "hi"
  • Access to parent using XMLId:
    C++
    class XMLElement
        {
        private:
    
            string el = "e";
            vector<shared_ptr<XMLElement>> children;
            vector<shared_ptr<XMLVariable>> variables;
            vector<shared_ptr<XMLContent>> contents;
            vector<shared_ptr<XMLComment>> comments;
            vector<shared_ptr<XMLCData>> cdatas;
            unsigned long long param = 0;
            XMLId parent = 0;
            XMLId id;
            
            static void CloneMirror(XMLElement& to,const XMLElement& from);
    
        public:
    
            XMLElement();
            XMLElement(const char*);
            XMLElement(const XMLElement&);
            XMLElement(XMLElement&&);
    
            
            XMLElement Mirror() const;
    
            const vector<shared_ptr<XMLComment>>& XMLElement::GetComments() const { return comments; }
            const vector<shared_ptr<XMLElement>>& XMLElement::GetChildren()  const { return children; }
            const vector<shared_ptr<XMLVariable>>& XMLElement::GetVariables() const { return variables; }
            const vector<shared_ptr<XMLCData>>& XMLElement::GetCDatas()  const { return cdatas; }
            const vector<shared_ptr<XMLContent>>& XMLElement::GetContents()  const { return contents; }
    
             vector<shared_ptr<XMLComment>>& XMLElement::GetComments() { return comments; }
             vector<shared_ptr<XMLElement>>& XMLElement::GetChildren()  { return children; }
             vector<shared_ptr<XMLVariable>>& XMLElement::GetVariables() { return variables; }
             vector<shared_ptr<XMLCData>>& XMLElement::GetCDatas()  { return cdatas; }
             vector<shared_ptr<XMLContent>>& XMLElement::GetContents()  { return contents; }
    
            // Operators
            bool operator==(const XMLElement& t) const;
            bool operator <(const XMLElement& x) const;
            XMLElement& operator =(const char*);
            
            // Gets
            XMLElement& operator [](size_t idx);
            XMLElement& operator [](const char* elm);
    
            const string& v(size_t idx) const;
            const string& v(const char* nn);
            string vd(const char*nn,const char*def = 0);
            string vd(const char*nn,const char*def = 0) const;
    
            string Content() const;
            XMLVariable& vv(const char* nn);
            unsigned long long GetElementParam() const;
            const string& GetElementName() const;
            void GetAllChildren(vector<shared_ptr<XMLElement>>& ch) const;
            shared_ptr<XMLElement> GetParent(shared_ptr<XMLElement> r) const;
            XMLElement* GetParent(XMLElement* r) const;
            size_t GetElementIndex(const XMLElement& e) const;
    
            // Sets
            void SetElementName(const char* x);
            void SetElementName(const wchar_t* x);
            void SetElementParam(unsigned long long p);
            void SortElements(std::function<bool(const shared_ptr<XMLElement>&e1,
                              const shared_ptr<XMLElement>&e2)>);
            void SortVariables(std::function<bool(const shared_ptr<XMLVariable>&e1,
                               const shared_ptr<XMLVariable>&e2)>);
            XML_ERROR XMLElement::MoveElement(size_t i,size_t y);
    
            // Find
            shared_ptr<XMLElement> FindElementZ(const char* n,bool ForceCreate = false);
            shared_ptr<XMLVariable> FindVariableZ(const char* n,bool ForceCreate = false,
                                    const char* defv = "");
            shared_ptr<XMLVariable> FindVariable(const char* n) const;
    
            // Inserts
            shared_ptr<XMLElement> InsertElement(size_t y,const XMLElement& x);
            shared_ptr<XMLElement> InsertElement(size_t y,XMLElement&& x);
            XMLElement& AddElement(const XMLElement& c);
            XMLElement& AddElement(XMLElement&& c);
            XMLElement& AddElement(const char* n = "");
            void AddElements(const std::initializer_list<string>& s);
            void SetVariables(const std::initializer_list<string>& s);
            XMLVariable& AddVariable(const char* vn = "n",const char* vv = "v",size_t p = -1);
            XMLVariable& AddVariable(const XMLVariable& v,size_t p = -1);
            XMLContent& AddContent(const char* pv,size_t ep,size_t p = -1);
            XMLComment& AddComment(const char* pv,size_t ep,size_t p = -1);
            XMLCData& AddCData(const char* pv,size_t ep,size_t p = -1);
    
            // Removals
            size_t RemoveAllElements();
            size_t RemoveElement(size_t i);
    
            shared_ptr<XMLElement> RemoveElementAndKeep(size_t i) throw(XML_ERROR);
    
            void clear();
    
            // Variables 
            size_t RemoveAllVariables();
    
            size_t RemoveVariable(size_t i);
    
            shared_ptr<XMLVariable> RemoveVariableAndKeep(size_t i) throw (XML_ERROR);
    
            string EorE(const string& s,bool N) const;
            string Serialize(bool NoEnc = false,size_t deep = 0) const;
    
            void Serialize(string& v,bool NoEnc = false,size_t deep = 0) const;
        };

XML

  • Construct empty, from ansi/unicode file, from memory.
  • Save to memory, file or FILE*.
  • operator = to parse text.
  • Contains an XMLHeader, an XMLDocType, a vector of XMLComment and the root XMLElement.
C++
class XML
    {
    private:

        bool UnicodeFile  = false;

        string fname;
        XMLHeader hdr;
        XMLDocType doctype;
        vector<shared_ptr<XMLComment>> hdrcomments;
        XMLElement root;

    public:

        // Constructors
        XML();

        XML(const char* file);

        XML(const wchar_t* file);

        XML(const char* mem,size_t l);

        void operator =(const char* d);

        // Savers
        size_t SaveFP(FILE* fp) const;

        XML_ERROR Save() const;
    
        
        XML_ERROR Save(const char* f) const;

        XML_ERROR Save(const wchar_t* f) const;

        // Loaders
        XML_PARSE ParseFile(FILE* fp);

        XML_PARSE Load(const char* f);

        XML_PARSE Load(const wchar_t* f);
        XML_PARSE Parse(const char* m,size_t len);

        // Gets
        XMLElement& XML::GetRootElement();
        XMLHeader& XML::GetHeader();
        size_t XML::MemoryUsage();

        // Sets
        void SetRootElement(XMLElement& newroot);
        void SetHeader(const XMLHeader& h);

        void Clear();


        void Version(XML_VERSION_INFO* x);


        // ser
        string Serialize(bool NoEnc = false) const;

    };

Example sample.xml

XML
<?xml version="1.0" standalone="yes" ?>
<!DOCTYPE catalog SYSTEM "catalog.dtd">
<!-- root comment 1 -->
<!-- root comment 2 -->
<catalog>
    <!-- cat comment 1 -->
    <product  description="Cardigan Sweater" product_image="cardigan.jpg" >
        <!-- pro comment 1 -->
        <catalog_item gender="Men's">
            <item_number>QWZ5671</item_number>
            <price>39.95</price>
            <![CDATA[ 
         hohoho
         dfsfd
         ^%$&^$*^*^#&^#$&^
         
         ]]>
            <size description="Medium">
            cont 1
                <color_swatch image="red_cardigan.jpg">Red</color_swatch>
            cont 2
                <color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
            cont 3
            </size>
            <size description="Large">
                <color_swatch image="red_cardigan.jpg">Red</color_swatch>
                <color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
            </size>
        </catalog_item>
   
    </product>
</catalog>

Parse it:

C++
using namespace XML3;
XML x("sample.xml");

auto&root = x.GetRootElement();
string v1 = root["product"].v(0); // Cardigan Sweater
string v2 = root["product"]["catalog_item"]["price"].GetContent(); // 39.95
string v3 = root.AddVariable("n","val").Serialize(); // created a new variable in root, n="val"

JSON

The helper XML3::JsonParser(XMLElement* r,const char* txt) helps you parse JSON into an XMLElement. It creates a <json> element inside r, and puts all JSON data there. Note that this is not a complete implementation of JSON.

History

  • 04/09/2018 Prepare for canonicalization and XAdES-T
  • 24/12/2015 Fixed case when <?xml?> in not closing the header
  • 04/11/2015 Fixed trimming in XMLContent
  • 29/10/2015 Removed MIME code and used Win32 API instead, also fixed GCC incompatibilities
  • 19/09/2015 Fixed case when <?xml?> without other spaces
  • 31/07/2015 Simplified BXML by using vector<char>
  • 13/07/2015 Added copy + move constructor to XML
  • 09/07/2015 More move semantics in BXML and XMLElement
  • 06/07/2015 Added move semantics for XMLElement Insert/Add element and fixed XMLVariable bug.
  • 14/06/2015 Bugfixes and speed enhancements
  • 06/06/2015 First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS, Android and Web (HTML/Javascript/CSS).

I 've a PhD in Digital Signal Processing and Artificial Intelligence and I specialize in Pro Audio and AI applications.

My home page: https://www.turbo-play.com

Comments and Discussions

 
Questionerror building project Pin
Member 1148805413-Feb-17 14:48
Member 1148805413-Feb-17 14:48 
AnswerRe: error building project Pin
Michael Chourdakis16-Feb-17 8:00
mvaMichael Chourdakis16-Feb-17 8:00 
QuestionWhy XML::MemoryUsage() returns 0? Pin
DBarzo26-Jul-16 1:03
DBarzo26-Jul-16 1:03 
AnswerRe: Why XML::MemoryUsage() returns 0? Pin
Michael Chourdakis26-Jul-16 2:21
mvaMichael Chourdakis26-Jul-16 2:21 
QuestionAwesome Once Again! Pin
koothkeeper25-Dec-15 6:41
professionalkoothkeeper25-Dec-15 6:41 
QuestionEmpty lines of indents following XMLContent Pin
Alasdair Craig3-Nov-15 0:28
Alasdair Craig3-Nov-15 0:28 
AnswerRe: Empty lines of indents following XMLContent Pin
Michael Chourdakis4-Nov-15 4:25
mvaMichael Chourdakis4-Nov-15 4:25 
QuestionHave you consider to post this as a tip? Pin
Nelek29-Oct-15 6:28
protectorNelek29-Oct-15 6:28 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA21-Sep-15 20:16
professionalȘtefan-Mihai MOGA21-Sep-15 20:16 
GeneralMy vote of 5 Pin
arroway3-Sep-15 22:40
arroway3-Sep-15 22:40 
QuestionBest C++ Article of June 2015 Pin
Sibeesh Passion9-Jul-15 18:57
professionalSibeesh Passion9-Jul-15 18:57 
AnswerRe: Best C++ Article of June 2015 Pin
Michael Chourdakis9-Jul-15 20:37
mvaMichael Chourdakis9-Jul-15 20:37 
SuggestionGreat compact library ! Thanks ! Could you help for some problems I encountered ? Pin
cth02713-Jun-15 0:56
cth02713-Jun-15 0:56 
GeneralRe: Great compact library ! Thanks ! Could you help for some problems I encountered ? Pin
Michael Chourdakis13-Jun-15 22:10
mvaMichael Chourdakis13-Jun-15 22:10 
GeneralRe: Great compact library ! Thanks ! Could you help for some problems I encountered ? Pin
cth02714-Jun-15 9:58
cth02714-Jun-15 9:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.