zen::Xml: dom.h Source File

| zen::Xml Simple C++ XML Processing

- Main Page
- Namespaces
- Classes

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
20 class XmlElement
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
zen::XmlDoc::root
const XmlElement & root() const
Get a const reference to the document's root element.
Definition: dom.h:264
zen::XmlElement::parent
const XmlElement * parent() const
Get parent XML element, may be nullptr for root element.
Definition: dom.h:194
zen::XmlElement::getValue
bool getValue(T &value) const
Get the value of this element as a user type.
Definition: dom.h:43
zen::XmlElement::removeAttribute
void removeAttribute(const String &name)
Remove the attribute with the given name.
Definition: dom.h:87
zen::XmlElement::getChildren
std::pair< ChildIterConst2, ChildIterConst2 > getChildren(const String &name) const
Access all child elements with the given name via STL iterators.
Definition: dom.h:162
zen::XmlDoc::setEncoding
void setEncoding(const String &encoding)
Set the encoding used in the XML declaration.
Definition: dom.h:294
zen::XmlElement::getChildren
std::pair< ChildIterConst, ChildIterConst > getChildren() const
Access all child elements sequentially via STL iterators.
Definition: dom.h:186
zen::readText
bool readText(const std::string &input, T &value)
Convert text to user data - used by XML elements and attributes.
Definition: cvrt_text.h:214
zen::XmlElement
An XML element.
Definition: dom.h:20
zen::XmlDoc::XmlDoc
XmlDoc(String rootName)
Definition: dom.h:261
zen::XmlElement::getChildren
std::pair< ChildIter, ChildIter > getChildren()
Definition: dom.h:189
zen::XmlElement::getChild
XmlElement * getChild(const String &name)
Definition: dom.h:119
zen::XmlElement::getAttribute
bool getAttribute(const String &name, T &value) const
Retrieve an attribute by name.
Definition: dom.h:61
zen
The zen::Xml namespace.
Definition: bind.h:15
zen::XmlDoc::setVersion
void setVersion(const String &version)
Set the version used in the XML declaration.
Definition: dom.h:280
zen::XmlDoc::setStandalone
void setStandalone(const String &standalone)
Set the standalone string used in the XML declaration.
Definition: dom.h:308
zen::XmlDoc
The complete XML document.
Definition: dom.h:246
zen::XmlDoc::XmlDoc
XmlDoc()
Default constructor setting up an empty XML document with a standard declaration: <...
Definition: dom.h:250
zen::XmlDoc::getEncodingAs
String getEncodingAs() const
Get the encoding used in the XML declaration.
Definition: dom.h:287
zen::XmlElement::addChild
XmlElement & addChild(const String &name)
Create a new child element and return a reference to it.
Definition: dom.h:95
zen::XmlDoc::root
XmlElement & root()
Get a reference to the document's root element.
Definition: dom.h:266
zen::XmlElement::getChild
const XmlElement * getChild(const String &name) const
Retrieve a child element with the given name.
Definition: dom.h:111
zen::readStruc
bool readStruc(const XmlElement &input, T &value)
Convert XML element to structured user data.
Definition: cvrt_struc.h:204
zen::XmlElement::parent
XmlElement * parent()
Get parent XML element, may be nullptr for root element.
Definition: dom.h:192
zen::XmlElement::setValue
void setValue(const T &value)
Set the value of this element.
Definition: dom.h:50
zen::XmlDoc::getVersionAs
String getVersionAs() const
Get the version used in the XML declaration.
Definition: dom.h:273
zen::XmlElement::setAttribute
void setAttribute(const String &name, const T &value)
Create or update an XML attribute.
Definition: dom.h:75
zen::writeStruc
void writeStruc(const T &value, XmlElement &output)
Convert structured user data into an XML element.
Definition: cvrt_struc.h:197
zen::XmlElement::getChildren
std::pair< ChildIter2, ChildIter2 > getChildren(const String &name)
Definition: dom.h:166
zen::XmlDoc::getStandaloneAs
String getStandaloneAs() const
Get the standalone string used in the XML declaration.
Definition: dom.h:301
zen::XmlElement::getNameAs
String getNameAs() const
Retrieve the name of this XML element.
Definition: dom.h:35
zen::writeText
void writeText(const T &value, std::string &output)
Convert user data into text - used by XML elements and attributes.
Definition: cvrt_text.h:207