zen::Xml
Simple C++ XML Processing
 All Classes Namespaces Functions Variables
dom.h
00001 // **************************************************************************
00002 // * This file is part of the zen::Xml project. It is distributed under the *
00003 // * Boost Software License: http://www.boost.org/LICENSE_1_0.txt           *
00004 // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved        *
00005 // **************************************************************************
00006 
00007 #ifndef ZEN_XML_DOM_HEADER_82085720723894567204564256
00008 #define ZEN_XML_DOM_HEADER_82085720723894567204564256
00009 
00010 #include <string>
00011 #include <vector>
00012 #include <memory>
00013 #include <map>
00014 #include "cvrt_text.h" //"readText/writeText"
00015 
00016 namespace zen
00017 {
00018 class XmlDoc;
00019 
00021 class XmlElement
00022 {
00023     struct PrivateConstruction {};
00024 public:
00025     //Construct an empty XML element
00026     //This constructor should be private, however std::make_shared() requires public access
00027     //Therefore at least prevent users from calling it via private dummy type PrivateConstruction
00028     template <class String>
00029     XmlElement(const String& name, XmlElement* parentElement, PrivateConstruction) : name_(utfCvrtTo<std::string>(name)), parent_(parentElement) {}
00030 
00032 
00036     template <class String>
00037     String getNameAs() const { return utfCvrtTo<String>(name_); }
00038 
00040 
00044     template <class T>
00045     bool getValue(T& value) const { return readStruc(*this, value); }
00046 
00048 
00051     template <class T>
00052     void setValue(const T& value) { writeStruc(value, *this); }
00053 
00055 
00062     template <class String, class T>
00063     bool getAttribute(const String& name, T& value) const
00064     {
00065         auto it = attributes.find(utfCvrtTo<std::string>(name));
00066         return it == attributes.end() ? false : readText(it->second, value);
00067     }
00068 
00070 
00076     template <class String, class T>
00077     void setAttribute(const String& name, const T& value)
00078     {
00079         std::string attrValue;
00080         writeText(value, attrValue);
00081         attributes[utfCvrtTo<std::string>(name)] = attrValue;
00082     }
00083 
00085 
00088     template <class String>
00089     void removeAttribute(const String& name) { attributes.erase(utfCvrtTo<std::string>(name)); }
00090 
00092 
00096     template <class String>
00097     XmlElement& addChild(const String& name)
00098     {
00099         std::string utf8Name = utfCvrtTo<std::string>(name);
00100         auto newElement = std::make_shared<XmlElement>(utf8Name, this, PrivateConstruction());
00101         childElements.push_back(newElement);
00102         childElementsSorted.insert(std::make_pair(utf8Name, newElement));
00103         return *newElement;
00104     }
00105 
00107 
00112     template <class String>
00113     const XmlElement* getChild(const String& name) const
00114     {
00115         auto it = childElementsSorted.find(utfCvrtTo<std::string>(name));
00116         return it == childElementsSorted.end() ? nullptr : &*(it->second);
00117     }
00118 
00120     template <class String>
00121     XmlElement* getChild(const String& name)
00122     {
00123         return const_cast<XmlElement*>(static_cast<const XmlElement*>(this)->getChild(name));
00124     }
00125 
00126     template < class IterTy,     //underlying iterator type
00127              class T,            //target object type
00128              class AccessPolicy > //access policy: see AccessPtrMap
00129     class PtrIter : public std::iterator<std::input_iterator_tag, T>, private AccessPolicy //get rid of shared_ptr indirection
00130     {
00131     public:
00132         PtrIter(IterTy it) : it_(it) {}
00133         PtrIter(const PtrIter& other) : it_(other.it_) {}
00134         PtrIter& operator++() { ++it_; return *this; }
00135         PtrIter operator++(int) { PtrIter tmp(*this); operator++(); return tmp; }
00136         inline friend bool operator==(const PtrIter& lhs, const PtrIter& rhs) { return lhs.it_ == rhs.it_; }
00137         inline friend bool operator!=(const PtrIter& lhs, const PtrIter& rhs) { return !(lhs == rhs); }
00138         T& operator* () { return  AccessPolicy::template objectRef<T>(it_); }
00139         T* operator->() { return &AccessPolicy::template objectRef<T>(it_); }
00140     private:
00141         IterTy it_;
00142     };
00143 
00144     struct AccessPtrMap
00145     {
00146         template <class T, class IterTy>
00147         T& objectRef(const IterTy& it) { return *(it->second); }
00148     };
00149 
00150     typedef PtrIter<std::multimap<std::string, std::shared_ptr<XmlElement>>::iterator, XmlElement, AccessPtrMap> ChildIter2;
00151     typedef PtrIter<std::multimap<std::string, std::shared_ptr<XmlElement>>::const_iterator, const XmlElement, AccessPtrMap> ChildIterConst2;
00152 
00154 
00163     template <class String>
00164     std::pair<ChildIterConst2, ChildIterConst2> getChildren(const String& name) const { return childElementsSorted.equal_range(utfCvrtTo<std::string>(name)); }
00165 
00167     template <class String>
00168     std::pair<ChildIter2, ChildIter2> getChildren(const String& name) { return childElementsSorted.equal_range(utfCvrtTo<std::string>(name)); }
00169 
00170     struct AccessPtrVec
00171     {
00172         template <class T, class IterTy>
00173         T& objectRef(const IterTy& it) { return **it; }
00174     };
00175 
00176     typedef PtrIter<std::vector<std::shared_ptr<XmlElement>>::iterator, XmlElement, AccessPtrVec> ChildIter;
00177     typedef PtrIter<std::vector<std::shared_ptr<XmlElement>>::const_iterator, const XmlElement, AccessPtrVec> ChildIterConst;
00178 
00180 
00188     std::pair<ChildIterConst, ChildIterConst> getChildren() const { return std::make_pair(childElements.begin(), childElements.end()); }
00189 
00191     std::pair<ChildIter, ChildIter> getChildren() { return std::make_pair(childElements.begin(), childElements.end()); }
00192 
00194     XmlElement* parent() { return parent_; };
00196     const XmlElement* parent() const { return parent_; };
00197 
00198 
00199     typedef std::map<std::string, std::string>::const_iterator AttrIter;
00200 
00201     /* -> disabled documentation extraction
00202       \brief Get all attributes associated with the element.
00203       \code
00204         auto iterPair = elem.getAttributes();
00205         for (auto it = iterPair.first; it != iterPair.second; ++it)
00206            std::cout << "name: " << it->first << " value: " << it->second << "\n";
00207       \endcode
00208       \return A pair of STL begin/end iterators to access all attributes sequentially as a list of name/value pairs of std::string.
00209     */
00210     std::pair<AttrIter, AttrIter> getAttributes() const { return std::make_pair(attributes.begin(), attributes.end()); }
00211 
00212     //Transactionally swap two elements.  -> disabled documentation extraction
00213     void swap(XmlElement& other)
00214     {
00215         name_     .swap(other.name_);
00216         value_    .swap(other.value_);
00217         attributes.swap(other.attributes);
00218         childElements.swap(other.childElements);
00219         childElementsSorted.swap(other.childElementsSorted);
00220         //std::swap(parent_, other.parent_); -> parent is physical location; update children's parent reference instead:
00221         std::for_each(      childElements.begin(),       childElements.end(), [&](const std::shared_ptr<XmlElement>& child) { child->parent_ = this;   });
00222         std::for_each(other.childElements.begin(), other.childElements.end(), [&](const std::shared_ptr<XmlElement>& child) { child->parent_ = &other; });
00223     }
00224 
00225 private:
00226     friend class XmlDoc;
00227 
00228     XmlElement(const XmlElement&);            //not implemented
00229     XmlElement& operator=(const XmlElement&); //
00230 
00231     std::string name_;
00232     std::string value_;
00233     std::map<std::string, std::string> attributes;
00234     std::vector<std::shared_ptr<XmlElement>>                childElements;       //all child elements in order of creation
00235     std::multimap<std::string, std::shared_ptr<XmlElement>> childElementsSorted; //alternate key: sorted by element name
00236     XmlElement* parent_;
00237 };
00238 
00239 
00240 //XmlElement::setValue<T>() calls zen::writeStruc() which calls XmlElement::setValue() ... => these two specializations end the circle
00241 template <> inline
00242 void XmlElement::setValue(const std::string& value) { value_ = value; }
00243 
00244 template <> inline
00245 bool XmlElement::getValue(std::string& value) const { value = value_; return true; }
00246 
00247 
00249 class XmlDoc
00250 {
00251 public:
00253     XmlDoc() : version_("1.0"), encoding_("UTF-8"), rootElement("Root", nullptr, XmlElement::PrivateConstruction()) {}
00254 
00255     //Setup an empty XML document
00260     template <class String>
00261     XmlDoc(String rootName) : version_("1.0"), encoding_("UTF-8"), rootElement(rootName, nullptr, XmlElement::PrivateConstruction()) {}
00262 
00264     const XmlElement& root() const { return rootElement; }
00266     XmlElement& root() { return rootElement; }
00267 
00269 
00272     template <class String>
00273     String getVersionAs() const { return utfCvrtTo<String>(version_); }
00274 
00276 
00279     template <class String>
00280     void setVersion(const String& version) { version_ = utfCvrtTo<std::string>(version); }
00281 
00283 
00286     template <class String>
00287     String getEncodingAs() const { return utfCvrtTo<String>(encoding_); }
00288 
00290 
00293     template <class String>
00294     void setEncoding(const String& encoding) { encoding_ = utfCvrtTo<std::string>(encoding); }
00295 
00297 
00300     template <class String>
00301     String getStandaloneAs() const { return utfCvrtTo<String>(standalone_); }
00302 
00304 
00307     template <class String>
00308     void setStandalone(const String& standalone) { standalone_ = utfCvrtTo<std::string>(standalone); }
00309 
00310 private:
00311     XmlDoc(const XmlDoc&);        //not implemented, thanks to XmlElement::parent_
00312     XmlDoc& operator=(const XmlDoc&); //
00313 
00314     std::string version_;
00315     std::string encoding_;
00316     std::string standalone_;
00317 
00318     XmlElement rootElement;
00319 };
00320 
00321 }
00322 
00323 #endif //ZEN_XML_DOM_HEADER_82085720723894567204564256