zen::Xml
Simple C++ XML Processing
|
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