zenXML
Straightforward C++ XML Processing
|
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