zen::Xml
Simple C++ XML Processing
 All Classes Namespaces Functions Variables Pages
bind.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 BIND_H_9081740816593478258435
8 #define BIND_H_9081740816593478258435
9 
10 #include <set>
11 #include "cvrt_struc.h"
12 #include "parser.h"
13 #include "io.h"
14 
15 namespace zen
16 {
22 
32 template <class String> inline
33 XmlDoc load(const String& filename) //throw XmlFileError, XmlParsingError
34 {
35  std::string stream = loadStream(filename); //throw XmlFileError
36  return parse(stream); //throw XmlParsingError
37 }
38 
39 
41 
51 template <class String> inline
52 void save(const XmlDoc& doc,
53  const String& filename,
54  const std::string& lineBreak = "\r\n",
55  const std::string& indent = " ") //throw XmlFileError
56 {
57  std::string stream = serialize(doc, lineBreak, indent); //throw ()
58  saveStream(stream, filename); //throw XmlFileError
59 }
60 
61 
63 class XmlOut
64 {
65 public:
67 
88  XmlOut(XmlDoc& doc) : ref_(&doc.root()) {}
90 
93  XmlOut(XmlElement& element) : ref_(&element) {}
94 
96 
101  template <class String>
102  XmlOut operator[](const String& name) const
103  {
104  const std::string utf8name = utfCvrtTo<std::string>(name);
105  XmlElement* child = ref_->getChild(utf8name);
106  return child ? *child : ref_->addChild(utf8name);
107  }
108 
110 
114  template <class T>
115  void operator()(const T& value) { writeStruc(value, *ref_); }
116 
118 
142  template <class String, class T>
143  void attribute(const String& name, const T& value) { ref_->setAttribute(name, value); }
144 
146  XmlElement& ref() { return *ref_; }
147 
148 private:
149  XmlElement* ref_; //always bound!
150 };
151 
152 
154 class XmlIn
155 {
156  class ErrorLog;
157 
158 public:
160 
170  XmlIn(const XmlDoc& doc) : log(std::make_shared<ErrorLog>()) { refList.push_back(&doc.root()); }
172 
175  XmlIn(const XmlElement* element) : log(std::make_shared<ErrorLog>()) { refList.push_back(element); }
177 
180  XmlIn(const XmlElement& element) : log(std::make_shared<ErrorLog>()) { refList.push_back(&element); }
181 
183 
188  template <class String>
189  XmlIn operator[](const String& name) const
190  {
191  std::vector<const XmlElement*> childList;
192 
193  if (refIndex < refList.size())
194  {
195  auto iterPair = refList[refIndex]->getChildren(name);
196  std::for_each(iterPair.first, iterPair.second,
197  [&](const XmlElement& child) { childList.push_back(&child); });
198  }
199 
200  return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log);
201  }
202 
204 
224  void next() { ++refIndex; }
225 
227 
232  template <class T>
233  bool operator()(T& value) const
234  {
235  if (refIndex < refList.size())
236  {
237  bool success = readStruc(*refList[refIndex], value);
238  if (!success)
239  log->notifyConversionError(getNameFormatted());
240  return success;
241  }
242  else
243  {
244  log->notifyMissingElement(getNameFormatted());
245  return false;
246  }
247  }
248 
250 
267  template <class String, class T>
268  bool attribute(const String& name, T& value) const
269  {
270  if (refIndex < refList.size())
271  {
272  bool success = refList[refIndex]->getAttribute(name, value);
273  if (!success)
274  log->notifyMissingAttribute(getNameFormatted(), utfCvrtTo<std::string>(name));
275  return success;
276  }
277  else
278  {
279  log->notifyMissingElement(getNameFormatted());
280  return false;
281  }
282  }
283 
285  const XmlElement* get() const { return refIndex < refList.size() ? refList[refIndex] : nullptr; }
286 
288 
297  explicit operator bool() const { return get() != nullptr; }
298 
300 
319  bool errorsOccured() const { return !log->elementList().empty(); }
320 
322 
326  template <class String>
327  std::vector<String> getErrorsAs() const
328  {
329  std::vector<String> output;
330  const auto& elements = log->elementList();
331  std::transform(elements.begin(), elements.end(), std::back_inserter(output), [](const std::string& str) { return utfCvrtTo<String>(str); });
332  return output;
333  }
334 
335 private:
336  XmlIn(const std::vector<const XmlElement*>& siblingList, const std::string& elementNameFmt, const std::shared_ptr<ErrorLog>& sharedlog) :
337  refList(siblingList), formattedName(elementNameFmt), log(sharedlog)
338  { assert((!siblingList.empty() && elementNameFmt.empty()) || (siblingList.empty() && !elementNameFmt.empty())); }
339 
340  static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>"
341  {
342  return (elem.parent() ? getNameFormatted(*elem.parent()) + " " : std::string()) + "<" + elem.getNameAs<std::string>() + ">";
343  }
344 
345  std::string getNameFormatted() const
346  {
347  if (refIndex < refList.size())
348  {
349  assert(formattedName.empty());
350  return getNameFormatted(*refList[refIndex]);
351  }
352  else
353  return formattedName;
354  }
355 
356  std::string getChildNameFormatted(const std::string& childName) const
357  {
358  std::string parentName = getNameFormatted();
359  return (parentName.empty() ? std::string() : (parentName + " ")) + "<" + childName + ">";
360  }
361 
362  class ErrorLog
363  {
364  public:
365  void notifyConversionError (const std::string& displayName) { insert(displayName); }
366  void notifyMissingElement (const std::string& displayName) { insert(displayName); }
367  void notifyMissingAttribute(const std::string& displayName, const std::string& attribName) { insert(displayName + " @" + attribName); }
368 
369  const std::vector<std::string>& elementList() const { return failedElements; }
370 
371  private:
372  void insert(const std::string& newVal)
373  {
374  if (usedElements.insert(newVal).second)
375  failedElements.push_back(newVal);
376  }
377 
378  std::vector<std::string> failedElements; //unique list of failed elements
379  std::set<std::string> usedElements;
380  };
381 
382  std::vector<const XmlElement*> refList; //all sibling elements with same name (all pointers bound!)
383  size_t refIndex = 0; //this sibling's index in refList
384  std::string formattedName; //contains full and formatted element name if (and only if) refList is empty
385  std::shared_ptr<ErrorLog> log; //always bound
386 };
387 }
388 
389 #endif //BIND_H_9081740816593478258435
bool errorsOccured() const
Notifies errors while mapping the XML to user data.
Definition: bind.h:319
void save(const XmlDoc &doc, const String &filename, const std::string &lineBreak="\r\n", const std::string &indent=" ")
Save XML document to a file.
Definition: bind.h:52
const XmlElement & root() const
Get a const reference to the document's root element.
Definition: dom.h:264
XmlDoc parse(const std::string &stream)
Load XML document from a byte stream.
Definition: parser.h:576
std::string serialize(const XmlDoc &doc, const std::string &lineBreak="\r\n", const std::string &indent=" ")
Save XML document as a byte stream.
Definition: parser.h:255
XmlOut(XmlDoc &doc)
Construct an output proxy for an XML document.
Definition: bind.h:88
XmlElement & ref()
Return a reference to the underlying Xml element.
Definition: bind.h:146
void saveStream(const std::string &stream, const String &filename)
Save byte stream to a file.
Definition: io.h:66
Proxy class to conveniently convert XML structure to user data.
Definition: bind.h:154
void operator()(const T &value)
Write user data to the underlying XML element.
Definition: bind.h:115
std::string loadStream(const String &filename)
Load byte stream from a file.
Definition: io.h:94
XmlIn(const XmlDoc &doc)
Construct an input proxy for an XML document.
Definition: bind.h:170
XmlIn(const XmlElement &element)
Construct an input proxy for a single XML element.
Definition: bind.h:180
void next()
Refer to next sibling element with the same name.
Definition: bind.h:224
STL namespace.
An XML element.
Definition: dom.h:20
void attribute(const String &name, const T &value)
Write user data to an XML attribute.
Definition: bind.h:143
The zen::Xml namespace.
Definition: bind.h:15
XmlIn operator[](const String &name) const
Retrieve a handle to an XML child element for reading.
Definition: bind.h:189
The complete XML document.
Definition: dom.h:246
bool attribute(const String &name, T &value) const
Read user data from an XML attribute.
Definition: bind.h:268
std::vector< String > getErrorsAs() const
Get a list of XML element and attribute names which failed to convert to user data.
Definition: bind.h:327
Proxy class to conveniently convert user data into XML structure.
Definition: bind.h:63
bool operator()(T &value) const
Read user data from the underlying XML element.
Definition: bind.h:233
XmlElement & addChild(const String &name)
Create a new child element and return a reference to it.
Definition: dom.h:95
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
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
XmlOut operator[](const String &name) const
Retrieve a handle to an XML child element for writing.
Definition: bind.h:102
XmlIn(const XmlElement *element)
Construct an input proxy for a single XML element, may be nullptr.
Definition: bind.h:175
XmlOut(XmlElement &element)
Construct an output proxy for a single XML element.
Definition: bind.h:93
XmlDoc load(const String &filename)
Load XML document from a file.
Definition: bind.h:33