Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++11

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

4.90/5 (34 votes)
3 Sep 2018CPOL2 min read 82.2K   1.5K  
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)