zen::Xml
Simple C++ XML Processing
 All Classes Namespaces Functions Variables Pages
dom.h
1 // *****************************************************************************
2 // * This file is part of the FreeFileSync project. It is distributed under *
3 // * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
4 // * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
5 // *****************************************************************************
6 
7 #ifndef DOM_H_82085720723894567204564256
8 #define DOM_H_82085720723894567204564256
9 
10 #include <string>
11 #include <map>
12 #include <zen/fixed_list.h>
13 #include "cvrt_text.h" //"readText/writeText"
14 
15 namespace zen
16 {
17 class XmlDoc;
18 
21 {
22 public:
23  XmlElement() : parent_(nullptr) {}
24 
25  //Construct an empty XML element
26  template <class String>
27  explicit XmlElement(const String& name, XmlElement* parentElement = nullptr) : name_(utfCvrtTo<std::string>(name)), parent_(parentElement) {}
28 
30 
34  template <class String>
35  String getNameAs() const { return utfCvrtTo<String>(name_); }
36 
38 
42  template <class T>
43  bool getValue(T& value) const { return readStruc(*this, value); }
44 
46 
49  template <class T>
50  void setValue(const T& value) { writeStruc(value, *this); }
51 
53 
60  template <class String, class T>
61  bool getAttribute(const String& name, T& value) const
62  {
63  auto it = attributes.find(utfCvrtTo<std::string>(name));
64  return it == attributes.end() ? false : readText(it->second, value);
65  }
66 
68 
74  template <class String, class T>
75  void setAttribute(const String& name, const T& value)
76  {
77  std::string attrValue;
78  writeText(value, attrValue);
79  attributes[utfCvrtTo<std::string>(name)] = attrValue;
80  }
81 
83 
86  template <class String>
87  void removeAttribute(const String& name) { attributes.erase(utfCvrtTo<std::string>(name)); }
88 
90 
94  template <class String>
95  XmlElement& addChild(const String& name)
96  {
97  std::string utf8Name = utfCvrtTo<std::string>(name);
98  childElements.emplace_back(utf8Name, this);
99  XmlElement& newElement = childElements.back();
100  childElementsSorted.emplace(utf8Name, &newElement);
101  return newElement;
102  }
103 
105 
110  template <class String>
111  const XmlElement* getChild(const String& name) const
112  {
113  auto it = childElementsSorted.find(utfCvrtTo<std::string>(name));
114  return it == childElementsSorted.end() ? nullptr : it->second;
115  }
116 
118  template <class String>
119  XmlElement* getChild(const String& name)
120  {
121  return const_cast<XmlElement*>(static_cast<const XmlElement*>(this)->getChild(name));
122  }
123 
124  template < class IterTy, //underlying iterator type
125  class T, //target object type
126  class AccessPolicy > //access policy: see AccessPtrMap
127  class PtrIter : public std::iterator<std::input_iterator_tag, T>, private AccessPolicy //get rid of shared_ptr indirection
128  {
129  public:
130  PtrIter(IterTy it) : it_(it) {}
131  PtrIter(const PtrIter& other) : it_(other.it_) {}
132  PtrIter& operator++() { ++it_; return *this; }
133  PtrIter operator++(int) { PtrIter tmp(*this); operator++(); return tmp; }
134  inline friend bool operator==(const PtrIter& lhs, const PtrIter& rhs) { return lhs.it_ == rhs.it_; }
135  inline friend bool operator!=(const PtrIter& lhs, const PtrIter& rhs) { return !(lhs == rhs); }
136  T& operator* () { return AccessPolicy::template objectRef<T>(it_); }
137  T* operator->() { return &AccessPolicy::template objectRef<T>(it_); }
138  private:
139  IterTy it_;
140  };
141 
142  struct AccessMapElement
143  {
144  template <class T, class IterTy>
145  T& objectRef(const IterTy& it) { return *(it->second); }
146  };
147 
148  using ChildIter2 = PtrIter<std::multimap<std::string, XmlElement*>::iterator, XmlElement, AccessMapElement>;
149  using ChildIterConst2 = PtrIter<std::multimap<std::string, XmlElement*>::const_iterator, const XmlElement, AccessMapElement>;
150 
152 
161  template <class String>
162  std::pair<ChildIterConst2, ChildIterConst2> getChildren(const String& name) const { return childElementsSorted.equal_range(utfCvrtTo<std::string>(name)); }
163 
165  template <class String>
166  std::pair<ChildIter2, ChildIter2> getChildren(const String& name) { return childElementsSorted.equal_range(utfCvrtTo<std::string>(name)); }
167 
168  struct AccessListElement
169  {
170  template <class T, class IterTy>
171  T& objectRef(const IterTy& it) { return *it; }
172  };
173 
174  using ChildIter = PtrIter<FixedList<XmlElement>::iterator, XmlElement, AccessListElement>;
175  using ChildIterConst = PtrIter<FixedList<XmlElement>::const_iterator, const XmlElement, AccessListElement>;
176 
178 
186  std::pair<ChildIterConst, ChildIterConst> getChildren() const { return std::make_pair(childElements.begin(), childElements.end()); }
187 
189  std::pair<ChildIter, ChildIter> getChildren() { return std::make_pair(childElements.begin(), childElements.end()); }
190 
192  XmlElement* parent() { return parent_; }
194  const XmlElement* parent() const { return parent_; }
195 
196  using AttrIter = std::map<std::string, std::string>::const_iterator;
197 
198  /* -> disabled documentation extraction
199  \brief Get all attributes associated with the element.
200  \code
201  auto iterPair = elem.getAttributes();
202  for (auto it = iterPair.first; it != iterPair.second; ++it)
203  std::cout << "name: " << it->first << " value: " << it->second << "\n";
204  \endcode
205  \return A pair of STL begin/end iterators to access all attributes sequentially as a list of name/value pairs of std::string.
206  */
207  std::pair<AttrIter, AttrIter> getAttributes() const { return std::make_pair(attributes.begin(), attributes.end()); }
208 
209  //swap two elements while keeping references to parent. -> disabled documentation extraction
210  void swapSubtree(XmlElement& other)
211  {
212  name_ .swap(other.name_);
213  value_ .swap(other.value_);
214  attributes.swap(other.attributes);
215  childElements.swap(other.childElements);
216  childElementsSorted.swap(other.childElementsSorted);
217  //std::swap(parent_, other.parent_); -> parent is physical location; update children's parent reference instead:
218  for (XmlElement& child : childElements)
219  child.parent_ = this;
220  for (XmlElement& child : other.childElements)
221  child.parent_ = &other;
222  }
223 
224 private:
225  XmlElement (const XmlElement&) = delete;
226  XmlElement& operator=(const XmlElement&) = delete;
227 
228  std::string name_;
229  std::string value_;
230  std::map<std::string, std::string> attributes;
231  FixedList<XmlElement> childElements; //all child elements in order of creation
232  std::multimap<std::string, XmlElement*> childElementsSorted; //alternate key: sorted by element name
233  XmlElement* parent_;
234 };
235 
236 
237 //XmlElement::setValue<T>() calls zen::writeStruc() which calls XmlElement::setValue() ... => these two specializations end the circle
238 template <> inline
239 void XmlElement::setValue(const std::string& value) { value_ = value; }
240 
241 template <> inline
242 bool XmlElement::getValue(std::string& value) const { value = value_; return true; }
243 
244 
246 class XmlDoc
247 {
248 public:
250  XmlDoc() : version_("1.0"), encoding_("UTF-8"), rootElement("Root") {}
251 
252  XmlDoc(XmlDoc&& tmp) { swap(tmp); }
253  XmlDoc& operator=(XmlDoc&& tmp) { swap(tmp); return *this; }
254 
255  //Setup an empty XML document
260  template <class String>
261  XmlDoc(String rootName) : version_("1.0"), encoding_("UTF-8"), rootElement(rootName) {}
262 
264  const XmlElement& root() const { return rootElement; }
266  XmlElement& root() { return rootElement; }
267 
269 
272  template <class String>
273  String getVersionAs() const { return utfCvrtTo<String>(version_); }
274 
276 
279  template <class String>
280  void setVersion(const String& version) { version_ = utfCvrtTo<std::string>(version); }
281 
283 
286  template <class String>
287  String getEncodingAs() const { return utfCvrtTo<String>(encoding_); }
288 
290 
293  template <class String>
294  void setEncoding(const String& encoding) { encoding_ = utfCvrtTo<std::string>(encoding); }
295 
297 
300  template <class String>
301  String getStandaloneAs() const { return utfCvrtTo<String>(standalone_); }
302 
304 
307  template <class String>
308  void setStandalone(const String& standalone) { standalone_ = utfCvrtTo<std::string>(standalone); }
309 
310  //Transactionally swap two elements. -> disabled documentation extraction
311  void swap(XmlDoc& other)
312  {
313  version_ .swap(other.version_);
314  encoding_ .swap(other.encoding_);
315  standalone_.swap(other.standalone_);
316  rootElement.swapSubtree(other.rootElement);
317  }
318 
319 private:
320  XmlDoc (const XmlDoc&) = delete; //not implemented, thanks to XmlElement::parent_
321  XmlDoc& operator=(const XmlDoc&) = delete;
322 
323  std::string version_;
324  std::string encoding_;
325  std::string standalone_;
326 
327  XmlElement rootElement;
328 };
329 
330 }
331 
332 #endif //DOM_H_82085720723894567204564256
const XmlElement & root() const
Get a const reference to the document's root element.
Definition: dom.h:264
const XmlElement * parent() const
Get parent XML element, may be nullptr for root element.
Definition: dom.h:194
bool getValue(T &value) const
Get the value of this element as a user type.
Definition: dom.h:43
void removeAttribute(const String &name)
Remove the attribute with the given name.
Definition: dom.h:87
std::pair< ChildIterConst2, ChildIterConst2 > getChildren(const String &name) const
Access all child elements with the given name via STL iterators.
Definition: dom.h:162
void setEncoding(const String &encoding)
Set the encoding used in the XML declaration.
Definition: dom.h:294
std::pair< ChildIterConst, ChildIterConst > getChildren() const
Access all child elements sequentially via STL iterators.
Definition: dom.h:186
bool readText(const std::string &input, T &value)
Convert text to user data - used by XML elements and attributes.
Definition: cvrt_text.h:214
An XML element.
Definition: dom.h:20
XmlDoc(String rootName)
Definition: dom.h:261
std::pair< ChildIter, ChildIter > getChildren()
Definition: dom.h:189
XmlElement * getChild(const String &name)
Definition: dom.h:119
bool getAttribute(const String &name, T &value) const
Retrieve an attribute by name.
Definition: dom.h:61
The zen::Xml namespace.
Definition: bind.h:15
void setVersion(const String &version)
Set the version used in the XML declaration.
Definition: dom.h:280
void setStandalone(const String &standalone)
Set the standalone string used in the XML declaration.
Definition: dom.h:308
The complete XML document.
Definition: dom.h:246
XmlDoc()
Default constructor setting up an empty XML document with a standard declaration: <...
Definition: dom.h:250
String getEncodingAs() const
Get the encoding used in the XML declaration.
Definition: dom.h:287
XmlElement & addChild(const String &name)
Create a new child element and return a reference to it.
Definition: dom.h:95
XmlElement & root()
Get a reference to the document's root element.
Definition: dom.h:266
const XmlElement * getChild(const String &name) const
Retrieve a child element with the given name.
Definition: dom.h:111
bool readStruc(const XmlElement &input, T &value)
Convert XML element to structured user data.
Definition: cvrt_struc.h:204
XmlElement * parent()
Get parent XML element, may be nullptr for root element.
Definition: dom.h:192
void setValue(const T &value)
Set the value of this element.
Definition: dom.h:50
String getVersionAs() const
Get the version used in the XML declaration.
Definition: dom.h:273
void setAttribute(const String &name, const T &value)
Create or update an XML attribute.
Definition: dom.h:75
void writeStruc(const T &value, XmlElement &output)
Convert structured user data into an XML element.
Definition: cvrt_struc.h:197
std::pair< ChildIter2, ChildIter2 > getChildren(const String &name)
Definition: dom.h:166
String getStandaloneAs() const
Get the standalone string used in the XML declaration.
Definition: dom.h:301
String getNameAs() const
Retrieve the name of this XML element.
Definition: dom.h:35
void writeText(const T &value, std::string &output)
Convert user data into text - used by XML elements and attributes.
Definition: cvrt_text.h:207