zen::Xml
Simple C++ XML Processing
 All Classes Namespaces Functions Variables
bind.h
00001 // **************************************************************************
00002 // * This file is part of the zen::Xml project. It is distributed under the *
00003 // * Boost Software License: http://www.boost.org/LICENSE_1_0.txt           *
00004 // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved        *
00005 // **************************************************************************
00006 
00007 #ifndef ZEN_XML_BIND_HEADER_9081740816593478258435
00008 #define ZEN_XML_BIND_HEADER_9081740816593478258435
00009 
00010 #include <set>
00011 #include "cvrt_struc.h"
00012 #include "parser.h"
00013 #include "io.h"
00014 
00015 namespace zen
00016 {
00022 
00023 
00032 template <class String> inline
00033 void load(const String& filename, XmlDoc& doc) //throw XmlFileError, XmlParsingError
00034 {
00035     std::string stream = loadStream(filename); //throw XmlFileError
00036     parse(stream, doc); //throw XmlParsingError
00037 }
00038 
00039 
00041 
00051 template <class String> inline
00052 void save(const XmlDoc& doc,
00053           const String& filename,
00054           const std::string& lineBreak = "\r\n",
00055           const std::string& indent = "    ") //throw XmlFileError
00056 {
00057     std::string stream = serialize(doc, lineBreak, indent); //throw ()
00058     saveStream(stream, filename); //throw XmlFileError
00059 }
00060 
00061 
00063 class XmlOut
00064 {
00065 public:
00067 
00088     XmlOut(XmlDoc& doc) : ref_(&doc.root()) {}
00090 
00093     XmlOut(XmlElement& element) : ref_(&element) {}
00094 
00096 
00101     template <class String>
00102     XmlOut operator[](const String& name) const
00103     {
00104         const std::string utf8name = utfCvrtTo<std::string>(name);
00105         XmlElement* child = ref_->getChild(utf8name);
00106         return child ? *child : ref_->addChild(utf8name);
00107     }
00108 
00110 
00114     template <class T>
00115     void operator()(const T& value) { writeStruc(value, *ref_); }
00116 
00118 
00142     template <class String, class T>
00143     void attribute(const String& name, const T& value) { ref_->setAttribute(name, value); }
00144 
00146     XmlElement& ref() { return *ref_; }
00147 
00148 private:
00149     XmlElement* ref_; //always bound!
00150 };
00151 
00152 
00154 class XmlIn
00155 {
00156     class ErrorLog;
00157     struct ConversionToBool { int dummy; };
00158 
00159 public:
00161 
00171     XmlIn(const XmlDoc& doc) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(&doc.root()); }
00173 
00176     XmlIn(const XmlElement* element) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(element); }
00178 
00181     XmlIn(const XmlElement& element) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(&element); }
00182 
00184 
00189     template <class String>
00190     XmlIn operator[](const String& name) const
00191     {
00192         std::vector<const XmlElement*> childList;
00193 
00194         if (refIndex < refList.size())
00195         {
00196             auto iterPair = refList[refIndex]->getChildren(name);
00197             std::for_each(iterPair.first, iterPair.second,
00198             [&](const XmlElement& child) { childList.push_back(&child); });
00199         }
00200 
00201         return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log);
00202     }
00203 
00205 
00225     void next() { ++refIndex; }
00226 
00228 
00233     template <class T>
00234     bool operator()(T& value) const
00235     {
00236         if (refIndex < refList.size())
00237         {
00238             bool success = readStruc(*refList[refIndex], value);
00239             if (!success)
00240                 log->notifyConversionError(getNameFormatted());
00241             return success;
00242         }
00243         else
00244         {
00245             log->notifyMissingElement(getNameFormatted());
00246             return false;
00247         }
00248     }
00249 
00251 
00268     template <class String, class T>
00269     bool attribute(const String& name, T& value) const
00270     {
00271         if (refIndex < refList.size())
00272         {
00273             bool success = refList[refIndex]->getAttribute(name, value);
00274             if (!success)
00275                 log->notifyMissingAttribute(getNameFormatted(), utfCvrtTo<std::string>(name));
00276             return success;
00277         }
00278         else
00279         {
00280             log->notifyMissingElement(getNameFormatted());
00281             return false;
00282         }
00283     }
00284 
00286     const XmlElement* get() const { return refIndex < refList.size() ? refList[refIndex] : nullptr; }
00287 
00289 
00298     operator int ConversionToBool::* () const { return get() ? &ConversionToBool::dummy : nullptr; }
00299 
00301 
00320     bool errorsOccured() const { return !log->elementList().empty(); }
00321 
00323 
00327     template <class String>
00328     std::vector<String> getErrorsAs() const
00329     {
00330         std::vector<String> output;
00331         const auto& elements = log->elementList();
00332         std::transform(elements.begin(), elements.end(), std::back_inserter(output), [](const std::string& str) { return utfCvrtTo<String>(str); });
00333         return output;
00334     }
00335 
00336 private:
00337     XmlIn(const std::vector<const XmlElement*>& siblingList, const std::string& elementNameFmt, const std::shared_ptr<ErrorLog>& sharedlog) :
00338         refList(siblingList), refIndex(0), formattedName(elementNameFmt), log(sharedlog)
00339     { assert((!siblingList.empty() && elementNameFmt.empty()) || (siblingList.empty() && !elementNameFmt.empty())); }
00340 
00341     static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>"
00342     {
00343         return (elem.parent() ? getNameFormatted(*elem.parent()) + " " : std::string()) + "<" + elem.getNameAs<std::string>() + ">";
00344     }
00345 
00346     std::string getNameFormatted() const
00347     {
00348         if (refIndex < refList.size())
00349         {
00350             assert(formattedName.empty());
00351             return getNameFormatted(*refList[refIndex]);
00352         }
00353         else
00354             return formattedName;
00355     }
00356 
00357     std::string getChildNameFormatted(const std::string& childName) const
00358     {
00359         std::string parentName = getNameFormatted();
00360         return (parentName.empty() ? std::string() : (parentName + " ")) + "<" + childName + ">";
00361     }
00362 
00363     class ErrorLog
00364     {
00365     public:
00366         void notifyConversionError (const std::string& formattedName)  { insert(formattedName); }
00367         void notifyMissingElement  (const std::string& formattedName)  { insert(formattedName); }
00368         void notifyMissingAttribute(const std::string& formattedName, const std::string& attribName) { insert(formattedName + " @" + attribName); }
00369 
00370         const std::vector<std::string>& elementList() const { return failedElements; }
00371 
00372     private:
00373         void insert(const std::string& newVal)
00374         {
00375             if (usedElements.insert(newVal).second)
00376                 failedElements.push_back(newVal);
00377         }
00378 
00379         std::vector<std::string> failedElements; //unique list of failed elements
00380         std::set<std::string>    usedElements;
00381     };
00382 
00383     std::vector<const XmlElement*> refList; //all sibling elements with same name (all pointers bound!)
00384     size_t refIndex;                        //this sibling's index in refList
00385     std::string formattedName;     //contains full and formatted element name if (and only if) refList is empty
00386     std::shared_ptr<ErrorLog> log; //always bound
00387 };
00388 }
00389 
00390 #endif //ZEN_XML_BIND_HEADER_9081740816593478258435