zenXML
Straightforward C++ XML Processing
zenxml_dom.h
00001 // **************************************************************************
00002 // * This file is part of the zenXML project. It is distributed under the   *
00003 // * Boost Software License, Version 1.0. See accompanying file             *
00004 // * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.       *
00005 // * Copyright (C) 2011 ZenJu (zhnmju123 AT gmx.de)                         *
00006 // **************************************************************************
00007 
00008 #ifndef ZEN_XML_DOM_HEADER_82085720723894567204564256
00009 #define ZEN_XML_DOM_HEADER_82085720723894567204564256
00010 
00011 #include <string>
00012 #include <vector>
00013 #include <map>
00014 #include <memory>
00015 #include "zenxml_cvrt.h"
00016 
00017 namespace zen
00018 {
00019 class XmlDoc;
00020 
00022 class XmlElement
00023 {
00024     struct PrivateConstruction {};
00025 
00026 public:
00027     //Construct an empty XML element
00028     //This constructor should be private, however std::make_shared() requires public access
00029     //Therefore at least prevent users from calling it via private dummy type PrivateConstruction
00030     template <class String>
00031     XmlElement(const String& name, XmlElement* parentElement, PrivateConstruction) : name_(toStdString(name)), parent_(parentElement) {}
00032 
00034 
00038     template <class String>
00039     String getNameAs() const { return stdStringTo<String>(name_); }
00040 
00042 
00046     template <class T>
00047     bool getValue(T& value) const { return readValue(*this, value); }
00048 
00050 
00053     template <class T>
00054     void setValue(const T& value) { writeValue(value, *this); }
00055 
00057 
00064     template <class String, class T>
00065     bool getAttribute(const String& name, T& value) const
00066     {
00067         auto iter = attributes.find(toStdString(name));
00068         return iter == attributes.end() ? false : readText(iter->second, value);
00069     }
00070 
00072 
00078     template <class String, class T>
00079     void setAttribute(const String& name, const T& value)
00080     {
00081         std::string attrValue;
00082         writeText(value, attrValue);
00083         attributes[toStdString(name)] = attrValue;
00084     } //create or update
00085 
00087 
00090     template <class String>
00091     void removeAttribute(const String& name) { attributes.erase(toStdString(name)); }
00092 
00094 
00098     template <class String>
00099     XmlElement& addChild(const String& name)
00100     {
00101         std::string utf8Name = toStdString(name);
00102         auto newElement = std::make_shared<XmlElement>(utf8Name, this, PrivateConstruction());
00103         //std::shared_ptr<XmlElement> newElement(new XmlElement(utf8Name, this));
00104         childElements.push_back(newElement);
00105         childElementsSorted.insert(std::make_pair(utf8Name, newElement));
00106         return *newElement;
00107     }
00108 
00110 
00115     template <class String>
00116     const XmlElement* getChild(const String& name) const
00117     {
00118         auto iter = childElementsSorted.find(toStdString(name));
00119         return iter == childElementsSorted.end() ? NULL : &*(iter->second);
00120     }
00121 
00123     template <class String>
00124     XmlElement* getChild(const String& name)
00125     {
00126         return const_cast<XmlElement*>(static_cast<const XmlElement*>(this)->getChild(name));
00127     }
00128 
00129     template <class IterTy,      //underlying iterator type
00130              class T,            //target object type
00131              class AccessPolicy> //access policy: see AccessPtrMap
00132     class PtrIter : public std::iterator<std::input_iterator_tag, T>, private AccessPolicy //get rid of shared_ptr indirection
00133     {
00134     public:
00135         PtrIter(IterTy it) : iter(it) {}
00136         PtrIter(const PtrIter& other) : iter(other.iter) {}
00137         PtrIter& operator++() { ++iter; return *this; }
00138         PtrIter operator++(int) { PtrIter tmp(*this); operator++(); return tmp; }
00139         inline friend bool operator==(const PtrIter& lhs, const PtrIter& rhs) { return lhs.iter == rhs.iter; }
00140         inline friend bool operator!=(const PtrIter& lhs, const PtrIter& rhs) { return !(lhs == rhs); }
00141         T& operator* () { return  AccessPolicy::template objectRef<T>(iter); }
00142         T* operator->() { return &AccessPolicy::template objectRef<T>(iter); }
00143     private:
00144         IterTy iter;
00145     };
00146 
00147     struct AccessPtrMap
00148     {
00149         template <class T, class IterTy>
00150         T& objectRef(const IterTy& iter) { return *(iter->second); }
00151     };
00152 
00153     typedef PtrIter<std::multimap<std::string, std::shared_ptr<XmlElement>>::iterator, XmlElement, AccessPtrMap> ChildIter2;
00154     typedef PtrIter<std::multimap<std::string, std::shared_ptr<XmlElement>>::const_iterator, const XmlElement, AccessPtrMap> ChildIterConst2;
00155 
00157 
00166     template <class String>
00167     std::pair<ChildIterConst2, ChildIterConst2> getChildren(const String& name) const { return childElementsSorted.equal_range(toStdString(name)); }
00168 
00170     template <class String>
00171     std::pair<ChildIter2, ChildIter2> getChildren(const String& name) { return childElementsSorted.equal_range(toStdString(name)); }
00172 
00173     struct AccessPtrVec
00174     {
00175         template <class T, class IterTy>
00176         T& objectRef(const IterTy& iter) { return **iter; }
00177     };
00178 
00179     typedef PtrIter<std::vector<std::shared_ptr<XmlElement>>::iterator, XmlElement, AccessPtrVec> ChildIter;
00180     typedef PtrIter<std::vector<std::shared_ptr<XmlElement>>::const_iterator, const XmlElement, AccessPtrVec> ChildIterConst;
00181 
00183 
00191     std::pair<ChildIterConst, ChildIterConst> getChildren() const { return std::make_pair(childElements.begin(), childElements.end()); }
00192 
00194     std::pair<ChildIter, ChildIter> getChildren() { return std::make_pair(childElements.begin(), childElements.end()); }
00195 
00197     XmlElement* parent() { return parent_; };
00199     const XmlElement* parent() const { return parent_; };
00200 
00201 
00202     typedef std::map<std::string, std::string>::const_iterator AttrIter;
00203 
00204     /* -> disabled documentation extraction
00205       \brief Get all attributes associated with the element.
00206       \code
00207         auto iterPair = elem.getAttributes();
00208         for (auto iter = iterPair.first; iter != iterPair.second; ++iter)
00209            std::cout << "name: " << iter->first << " value: " << iter->second << "\n";
00210       \endcode
00211       \return A pair of STL begin/end iterators to access all attributes sequentially as a list of name/value pairs of std::string.
00212     */
00213     std::pair<AttrIter, AttrIter> getAttributes() const { return std::make_pair(attributes.begin(), attributes.end()); }
00214 
00215     //Transactionally swap two elements.  -> disabled documentation extraction
00216     void swap(XmlElement& other)
00217     {
00218         name_     .swap(other.name_);
00219         value_    .swap(other.value_);
00220         attributes.swap(other.attributes);
00221         childElements.swap(other.childElements);
00222         childElementsSorted.swap(other.childElementsSorted);
00223         //std::swap(parent_, other.parent_); -> parent is physical location; update children's parent reference instead:
00224         std::for_each(      childElements.begin(),       childElements.end(), [&](const std::shared_ptr<XmlElement>& child) { child->parent_ = this;   });
00225         std::for_each(other.childElements.begin(), other.childElements.end(), [&](const std::shared_ptr<XmlElement>& child) { child->parent_ = &other; });
00226     }
00227 
00228 private:
00229     friend class XmlDoc;
00230 
00231     XmlElement(const XmlElement&);            //not implemented
00232     XmlElement& operator=(const XmlElement&); //
00233 
00234     std::string name_;
00235     std::string value_;
00236     std::map<std::string, std::string> attributes;
00237     std::vector<std::shared_ptr<XmlElement>>                childElements;       //all child elements in order of creation
00238     std::multimap<std::string, std::shared_ptr<XmlElement>> childElementsSorted; //alternate key: sorted by element name
00239     XmlElement* parent_;
00240 };
00241 
00242 
00243 //XmlElement::setValue<T>() calls zen::writeValue() which calls XmlElement::setValue() ... => these two specializations end the circle
00244 template <> inline
00245 void XmlElement::setValue(const std::string& value) { value_ = value; }
00246 
00247 template <> inline
00248 bool XmlElement::getValue(std::string& value) const { value = value_; return true; }
00249 
00250 
00252 class XmlDoc
00253 {
00254 public:
00256     XmlDoc() : version_("1.0"), encoding_("UTF-8"), rootElement("Root", NULL, XmlElement::PrivateConstruction()) {}
00257 
00258     //Setup an empty XML document
00263     template <class String>
00264     XmlDoc(String rootName) : version_("1.0"), encoding_("UTF-8"), rootElement(rootName, NULL, XmlElement::PrivateConstruction()) {}
00265 
00267     const XmlElement& root() const { return rootElement; }
00269     XmlElement& root() { return rootElement; }
00270 
00272 
00275     template <class String>
00276     String getVersionAs() const { return stdStringTo<String>(version_); }
00277 
00279 
00282     template <class String>
00283     void setVersion(const String& version) { version_ = toStdString(version); }
00284 
00286 
00289     template <class String>
00290     String getEncodingAs() const { return stdStringTo<String>(encoding_); }
00291 
00293 
00296     template <class String>
00297     void setEncoding(const String& encoding) { encoding_ = toStdString(encoding); }
00298 
00300 
00303     template <class String>
00304     String getStandaloneAs() const { return stdStringTo<String>(standalone_); }
00305 
00307 
00310     template <class String>
00311     void setStandalone(const String& standalone) { standalone_ = toStdString(standalone); }
00312 
00313 private:
00314     XmlDoc(const XmlDoc&);        //not implemented, thanks to XmlElement::parent_
00315     XmlDoc& operator=(const XmlDoc&); //
00316 
00317     std::string version_;
00318     std::string encoding_;
00319     std::string standalone_;
00320 
00321     XmlElement rootElement;
00322 };
00323 
00324 }
00325 
00326 #endif //ZEN_XML_DOM_HEADER_82085720723894567204564256
 All Classes Namespaces Functions Variables