zenXML
Straightforward C++ XML Processing
|
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