zenXML
Straightforward C++ XML Processing
zenxml_bind.h
00001 // **************************************************************************
00002 // * This file is part of the zenXML project. It is distributed under the   *
00003 // * Boost Software License, Version 1.0. See accompanying file             *
00004 // * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.       *
00005 // * Copyright (C) 2011 ZenJu (zhnmju123 AT gmx.de)                         *
00006 // **************************************************************************
00007 
00008 #ifndef ZEN_XML_BIND_HEADER_9081740816593478258435
00009 #define ZEN_XML_BIND_HEADER_9081740816593478258435
00010 
00011 #include <set>
00012 #include "zenxml_cvrt.h"
00013 #include "zenxml_parser.h"
00014 #include "zenxml_io.h"
00015 
00016 namespace zen
00017 {
00023 
00024 
00033 template <class String> inline
00034 void load(const String& filename, XmlDoc& doc) //throw XmlFileError, XmlParsingError
00035 {
00036     std::string stream = loadStream(filename); //throw XmlFileError
00037     parse(stream, doc); //throw XmlParsingError
00038 }
00039 
00040 
00042 
00052 template <class String> inline
00053 void save(const XmlDoc& doc,
00054           const String& filename,
00055           const std::string& lineBreak = "\r\n",
00056           const std::string& indent = "    ") //throw XmlFileError
00057 {
00058     std::string stream = serialize(doc, lineBreak, indent); //throw ()
00059     saveStream(stream, filename); //throw XmlFileError
00060 }
00061 
00062 
00064 class XmlOut
00065 {
00066 public:
00068 
00089     XmlOut(XmlDoc& doc)         : ref_(&doc.root()) {}
00091 
00094     XmlOut(XmlElement& element) : ref_(&element) {}
00095 
00097 
00102     template <class String>
00103     XmlOut operator[](const String& name) const
00104     {
00105         const std::string utf8name = toStdString(name);
00106         XmlElement* child = ref_->getChild(utf8name);
00107         return child ? *child : ref_->addChild(utf8name);
00108     }
00109 
00111 
00115     template <class T>
00116     void operator()(const T& value) { writeValue(value, *ref_); }
00117 
00119 
00143     template <class String, class T>
00144     void attribute(const String& name, const T& value) { ref_->setAttribute(name, value); }
00145 
00147     XmlElement& ref() { return *ref_; }
00148 
00149 private:
00150     XmlElement* ref_; //always bound!
00151 };
00152 
00153 
00155 class XmlIn
00156 {
00157     class ErrorLog;
00158     struct ConversionToBool { int dummy; };
00159 
00160 public:
00162 
00172     XmlIn(const XmlDoc& doc) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(&doc.root()); }
00174 
00177     XmlIn(const XmlElement* element) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(element); }
00179 
00182     XmlIn(const XmlElement& element) : refIndex(0), log(std::make_shared<ErrorLog>()) { refList.push_back(&element); }
00183 
00185 
00190     template <class String>
00191     XmlIn operator[](const String& name) const
00192     {
00193         std::vector<const XmlElement*> childList;
00194 
00195         if (refIndex < refList.size())
00196         {
00197             auto iterPair = refList[refIndex]->getChildren(name);
00198             std::for_each(iterPair.first, iterPair.second,
00199             [&](const XmlElement& child) { childList.push_back(&child); });
00200         }
00201 
00202         return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log);
00203     }
00204 
00206 
00226     void next() { ++refIndex; }
00227 
00229 
00234     template <class T>
00235     bool operator()(T& value) const
00236     {
00237         if (refIndex < refList.size())
00238         {
00239             bool success = readValue(*refList[refIndex], value);
00240             if (!success)
00241                 log->notifyConversionError(getNameFormatted());
00242             return success;
00243         }
00244         else
00245         {
00246             log->notifyMissingElement(getNameFormatted());
00247             return false;
00248         }
00249     }
00250 
00252 
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(), toStdString(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] : NULL; }
00287 
00289 
00298     operator int ConversionToBool::* () const { return get() ? &ConversionToBool::dummy : NULL; }
00299 
00301 
00320     bool errorsOccured() const { return log->errorsOccured(); }
00321 
00323 
00327     template <class String>
00328     std::vector<String> getErrorsAs() const { return log->getErrorsAs<String>(); }
00329 
00330 private:
00331     XmlIn(const std::vector<const XmlElement*>& siblingList, const std::string& elementNameFmt, const std::shared_ptr<ErrorLog>& sharedlog) :
00332         refList(siblingList), refIndex(0), formattedName(elementNameFmt), log(sharedlog)
00333     { assert((!siblingList.empty() && elementNameFmt.empty()) || (siblingList.empty() && !elementNameFmt.empty())); }
00334 
00335     static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>"
00336     {
00337         return (elem.parent() ? getNameFormatted(*elem.parent()) + " " : std::string()) + "<" + elem.getNameAs<std::string>() + ">";
00338     }
00339 
00340     std::string getNameFormatted() const
00341     {
00342         if (refIndex < refList.size())
00343         {
00344             assert(formattedName.empty());
00345             return getNameFormatted(*refList[refIndex]);
00346         }
00347         else
00348             return formattedName;
00349     }
00350 
00351     std::string getChildNameFormatted(const std::string& childName) const
00352     {
00353         std::string parentName = getNameFormatted();
00354         return (parentName.empty() ? std::string() : (parentName + " ")) + "<" + childName + ">";
00355     }
00356 
00357     template <class T>
00358     class UniqueList
00359     {
00360     public:
00361         void add(const T& newVal)
00362         {
00363             if (sorted.find(newVal) == sorted.end())
00364             {
00365                 sorted.insert(newVal);
00366                 sequence.push_back(newVal);
00367             }
00368         }
00369 
00370         const std::vector<T>& ref() const { return sequence; }
00371 
00372     private:
00373         std::vector<T> sequence;
00374         std::set<T>    sorted;
00375     };
00376 
00377     class ErrorLog      //Implementation of the ErrorPolicy as used by XmlIn
00378     {
00379     public:
00380         void notifyConversionError (const std::string& formattedName)  { failedReads.add(formattedName); }
00381         void notifyMissingElement  (const std::string& formattedName)  { failedReads.add(formattedName); }
00382         void notifyMissingAttribute(const std::string& formattedName, const std::string& attribName) { failedReads.add(formattedName + " @" + attribName); }
00383 
00384         bool errorsOccured() const { return !failedReads.ref().empty(); }
00385 
00386         template <class String>
00387         std::vector<String> getErrorsAs() const
00388         {
00389             std::vector<String> output;
00390             std::transform(failedReads.ref().begin(), failedReads.ref().end(), std::back_inserter(output), [](const std::string& str) { return stdStringTo<String>(str); });
00391             return output;
00392         }
00393 
00394     private:
00395         UniqueList<std::string> failedReads;
00396     };
00397 
00398     std::vector<const XmlElement*> refList; //all sibling elements with same name (all pointers bound!)
00399     size_t refIndex;                        //this sibling's index in refList
00400     std::string formattedName;     //contains full and formatted element name if (and only if) refList is empty
00401     std::shared_ptr<ErrorLog> log; //always bound
00402 };
00403 }
00404 
00405 #endif //ZEN_XML_BIND_HEADER_9081740816593478258435
 All Classes Namespaces Functions Variables