zen::Xml
Simple C++ XML Processing
|
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