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.html *
4 // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
5 // **************************************************************************
6 
7 #ifndef ZEN_XML_BIND_HEADER_9081740816593478258435
8 #define ZEN_XML_BIND_HEADER_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  struct ConversionToBool { int dummy; };
158 
159 public:
161 
171  XmlIn(const XmlDoc& doc) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(&doc.root()); }
173 
176  XmlIn(const XmlElement* element) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(element); }
178 
181  XmlIn(const XmlElement& element) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(&element); }
182 
184 
189  template <class String>
190  XmlIn operator[](const String& name) const
191  {
192  std::vector<const XmlElement*> childList;
193 
194  if (refIndex < refList.size())
195  {
196  auto iterPair = refList[refIndex]->getChildren(name);
197  std::for_each(iterPair.first, iterPair.second,
198  [&](const XmlElement& child) { childList.push_back(&child); });
199  }
200 
201  return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log);
202  }
203 
205 
225  void next() { ++refIndex; }
226 
228 
233  template <class T>
234  bool operator()(T& value) const
235  {
236  if (refIndex < refList.size())
237  {
238  bool success = readStruc(*refList[refIndex], value);
239  if (!success)
240  log->notifyConversionError(getNameFormatted());
241  return success;
242  }
243  else
244  {
245  log->notifyMissingElement(getNameFormatted());
246  return false;
247  }
248  }
249 
251 
268  template <class String, class T>
269  bool attribute(const String& name, T& value) const
270  {
271  if (refIndex < refList.size())
272  {
273  bool success = refList[refIndex]->getAttribute(name, value);
274  if (!success)
275  log->notifyMissingAttribute(getNameFormatted(), utfCvrtTo<std::string>(name));
276  return success;
277  }
278  else
279  {
280  log->notifyMissingElement(getNameFormatted());
281  return false;
282  }
283  }
284 
286  const XmlElement* get() const { return refIndex < refList.size() ? refList[refIndex] : nullptr; }
287 
289 
298  operator int ConversionToBool::* () const { return get() ? &ConversionToBool::dummy : nullptr; }
299 
301 
320  bool errorsOccured() const { return !log->elementList().empty(); }
321 
323 
327  template <class String>
328  std::vector<String> getErrorsAs() const
329  {
330  std::vector<String> output;
331  const auto& elements = log->elementList();
332  std::transform(elements.begin(), elements.end(), std::back_inserter(output), [](const std::string& str) { return utfCvrtTo<String>(str); });
333  return output;
334  }
335 
336 private:
337  XmlIn(const std::vector<const XmlElement*>& siblingList, const std::string& elementNameFmt, const std::shared_ptr<ErrorLog>& sharedlog) :
338  refList(siblingList), refIndex(0), formattedName(elementNameFmt), log(sharedlog)
339  { assert((!siblingList.empty() && elementNameFmt.empty()) || (siblingList.empty() && !elementNameFmt.empty())); }
340 
341  static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>"
342  {
343  return (elem.parent() ? getNameFormatted(*elem.parent()) + " " : std::string()) + "<" + elem.getNameAs<std::string>() + ">";
344  }
345 
346  std::string getNameFormatted() const
347  {
348  if (refIndex < refList.size())
349  {
350  assert(formattedName.empty());
351  return getNameFormatted(*refList[refIndex]);
352  }
353  else
354  return formattedName;
355  }
356 
357  std::string getChildNameFormatted(const std::string& childName) const
358  {
359  std::string parentName = getNameFormatted();
360  return (parentName.empty() ? std::string() : (parentName + " ")) + "<" + childName + ">";
361  }
362 
363  class ErrorLog
364  {
365  public:
366  void notifyConversionError (const std::string& formattedName) { insert(formattedName); }
367  void notifyMissingElement (const std::string& formattedName) { insert(formattedName); }
368  void notifyMissingAttribute(const std::string& formattedName, const std::string& attribName) { insert(formattedName + " @" + attribName); }
369 
370  const std::vector<std::string>& elementList() const { return failedElements; }
371 
372  private:
373  void insert(const std::string& newVal)
374  {
375  if (usedElements.insert(newVal).second)
376  failedElements.push_back(newVal);
377  }
378 
379  std::vector<std::string> failedElements; //unique list of failed elements
380  std::set<std::string> usedElements;
381  };
382 
383  std::vector<const XmlElement*> refList; //all sibling elements with same name (all pointers bound!)
384  size_t refIndex; //this sibling's index in refList
385  std::string formattedName; //contains full and formatted element name if (and only if) refList is empty
386  std::shared_ptr<ErrorLog> log; //always bound
387 };
388 }
389 
390 #endif //ZEN_XML_BIND_HEADER_9081740816593478258435
bool errorsOccured() const
Notifies errors while mapping the XML to user data.
Definition: bind.h:320
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:267
XmlDoc parse(const std::string &stream)
Load XML document from a byte stream.
Definition: parser.h:612
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:287
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:171
XmlIn(const XmlElement &element)
Construct an input proxy for a single XML element.
Definition: bind.h:181
void next()
Refer to next sibling element with the same name.
Definition: bind.h:225
An XML element.
Definition: dom.h:21
void attribute(const String &name, const T &value)
Write user data to an XML attribute.
Definition: bind.h:143
XmlIn operator[](const String &name) const
Retrieve a handle to an XML child element for reading.
Definition: bind.h:190
The complete XML document.
Definition: dom.h:249
bool attribute(const String &name, T &value) const
Read user data from an XML attribute.
Definition: bind.h:269
std::vector< String > getErrorsAs() const
Get a list of XML element and attribute names which failed to convert to user data.
Definition: bind.h:328
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:234
XmlElement & addChild(const String &name)
Create a new child element and return a reference to it.
Definition: dom.h:97
const XmlElement * getChild(const String &name) const
Retrieve a child element with the given name.
Definition: dom.h:113
bool readStruc(const XmlElement &input, T &value)
Convert XML element to structured user data.
Definition: cvrt_struc.h:205
void setAttribute(const String &name, const T &value)
Create or update an XML attribute.
Definition: dom.h:77
void writeStruc(const T &value, XmlElement &output)
Convert structured user data into an XML element.
Definition: cvrt_struc.h:198
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:176
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