Click here to Skip to main content
13,627,789 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

49.5K views
1.5K downloads
56 bookmarked
Posted 12 Jun 2015
Licenced CPOL

XML++ version 3: The C++11 update of my XML Library

, 26 Dec 2015
Rate this:
Please Sign up or sign in to vote.
The update to my beloved library.

 

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.

// 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: 
      XMLContent v("n");
    • Another Variable:
      XMLContent v2 = v;
  • Enhancements
    • Set value:
      v2 = "hello";
    • Binary contents:
      v2.SetBinaryData("\0\0\0",3);
    • operator const char*():
      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.
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.

 

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.
    vector<shared_ptr<XMLElement>> v = el.GetChildren();
     
  • Access to elements via operator [] and an index:
    el[0].vv["animal"] = "rabbit";
     
  • Access via operator [] and a string, creates children if they do not exist:
    el["hello"]["there"] = "<there v=\"test\">";
     
  • Access to attributes via v() with index or variable name, or with vv() for the full XMLVariable:
    string g = el.v("t");
     
  • Copy or mirror:
    XMLElement e1 = "<e v=\"hi\">";<br />
    	XMLElement e2 = e1;<br />
    	XMLElement e3 = e1.Mirror();<br />
    	e1.vv("v") = "hello"; // e3 variable is changed as well, e2 still "hi"

     
  • Access to parent using XMLId
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 a XMLHeader, a XMLDocType, a vector of XMLComment and the root XMLElement.
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 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:

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 implenentation of JSON.

 

History

  • 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)

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

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

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Pro

Comments and Discussions

 
Questionerror building project Pin
Member 1148805413-Feb-17 14:48
memberMember 1148805413-Feb-17 14:48 
AnswerRe: error building project Pin
Michael Chourdakis16-Feb-17 8:00
memberMichael Chourdakis16-Feb-17 8:00 
QuestionWhy XML::MemoryUsage() returns 0? Pin
DennyBarzo26-Jul-16 1:03
memberDennyBarzo26-Jul-16 1:03 
AnswerRe: Why XML::MemoryUsage() returns 0? Pin
Michael Chourdakis26-Jul-16 2:21
mvpMichael 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
memberAlasdair Craig3-Nov-15 0:28 
AnswerRe: Empty lines of indents following XMLContent Pin
Michael Chourdakis4-Nov-15 4:25
memberMichael 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
Mihai MOGA21-Sep-15 20:16
professionalMihai MOGA21-Sep-15 20:16 
GeneralMy vote of 5 Pin
arroway3-Sep-15 22:40
memberarroway3-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
memberMichael Chourdakis9-Jul-15 20:37 
SuggestionGreat compact library ! Thanks ! Could you help for some problems I encountered ? Pin
cth02713-Jun-15 0:56
membercth02713-Jun-15 0:56 
GeneralRe: Great compact library ! Thanks ! Could you help for some problems I encountered ? Pin
Michael Chourdakis13-Jun-15 22:10
memberMichael Chourdakis13-Jun-15 22:10 
GeneralRe: Great compact library ! Thanks ! Could you help for some problems I encountered ? Pin
cth02714-Jun-15 9:58
membercth02714-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.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web04 | 2.8.180712.1 | Last Updated 26 Dec 2015
Article Copyright 2015 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid