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_CONVERT_HEADER_018727409908342709743 00009 #define ZEN_XML_CONVERT_HEADER_018727409908342709743 00010 00011 #include "string_utf8.h" 00012 #include "string_tools.h" 00013 //#include <loki/TypeTraits.h> -> include implicitly via <string_tools.h>! -> specialized __int64 00014 #include "zenxml_dom.h" 00015 00016 namespace zen 00017 { 00063 00064 00070 template <class T> bool readValue(const XmlElement& input, T& value); 00072 00077 template <class T> void writeValue(const T& value, XmlElement& output); 00078 00079 00081 00087 template <class T> bool readText(const std::string& input, T& value); 00089 00094 template <class T> void writeText(const T& value, std::string& output); 00095 00096 00097 /* Different classes of data types: 00098 00099 --------------------------- 00100 | structured | readValue/writeValue - e.g. string-convertible types, STL containers, std::pair, structured user types 00101 | ---------------------- | 00102 | | string-convertible | | readText/writeText - e.g. string-like types, all built-in arithmetic numbers, bool 00103 | | --------------- | | 00104 | | | string-like | | | utf8CvrtTo - e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... 00105 | | --------------- | | 00106 | ---------------------- | 00107 --------------------------- 00108 */ 00109 00110 00111 00112 00113 00114 00115 00116 00117 00118 00119 00120 00121 00122 00123 00124 00125 00126 00127 00128 00129 00130 00131 //------------------------------ implementation ------------------------------------- 00132 namespace implementation 00133 { 00134 template <typename T> 00135 class HasStlContainerMemberTypes 00136 { 00137 typedef char Yes[1]; 00138 typedef char No [2]; 00139 00140 //detect presence of member type names 00141 template <typename U> class HelperTp {}; 00142 00143 template <class U> static Yes& hasMemberValueType(HelperTp<typename U::value_type>*); 00144 template <class U> static No& hasMemberValueType(...); 00145 00146 template <class U> static Yes& hasMemberIterator(HelperTp<typename U::iterator>*); 00147 template <class U> static No& hasMemberIterator(...); 00148 00149 template <class U> static Yes& hasMemberConstIterator(HelperTp<typename U::const_iterator>*); 00150 template <class U> static No& hasMemberConstIterator(...); 00151 00152 public: 00153 enum { Result = sizeof(hasMemberValueType <T>(NULL)) == sizeof(Yes) && 00154 sizeof(hasMemberIterator <T>(NULL)) == sizeof(Yes) && 00155 sizeof(hasMemberConstIterator<T>(NULL)) == sizeof(Yes) 00156 }; 00157 }; 00158 00159 00160 template <typename T, bool isClassType> 00161 class HasStlContainerMemberFun 00162 { 00163 public: 00164 enum { Result = false}; 00165 }; 00166 00167 template <typename T> 00168 class HasStlContainerMemberFun<T, true> //T must be class-type! 00169 { 00170 typedef char Yes[1]; 00171 typedef char No [2]; 00172 00173 //detect presence of member variables (within T or one of it's base classes) 00174 template <typename U, U t> class HelperFn {}; 00175 00176 struct Fallback 00177 { 00178 int begin; 00179 int end; 00180 int insert; 00181 }; 00182 00183 template <class U> 00184 struct Helper2 : public U, public Fallback {}; //U must be a class-type! 00185 00186 //we don't know the exact declaration of the member attribute (may be in base class), but we know what NOT to expect: 00187 template <class U> static No& hasMemberBegin(HelperFn<int Fallback::*, &Helper2<U>::begin>*); 00188 template <class U> static Yes& hasMemberBegin(...); 00189 00190 template <class U> static No& hasMemberEnd(HelperFn<int Fallback::*, &Helper2<U>::end>*); 00191 template <class U> static Yes& hasMemberEnd(...); 00192 00193 template <class U> static No& hasMemberInsert(HelperFn<int Fallback::*, &Helper2<U>::insert>*); 00194 template <class U> static Yes& hasMemberInsert(...); 00195 00196 public: 00197 enum { Result = sizeof(hasMemberBegin <T>(NULL)) == sizeof(Yes) && 00198 sizeof(hasMemberEnd <T>(NULL)) == sizeof(Yes) && 00199 sizeof(hasMemberInsert<T>(NULL)) == sizeof(Yes) 00200 }; 00201 }; 00202 } 00203 00204 template <typename T> 00205 class IsStlContainer 00206 { 00207 public: 00208 enum { Result = implementation::HasStlContainerMemberFun<T, implementation::HasStlContainerMemberTypes<T>::Result>::Result }; 00209 }; 00210 00211 00212 namespace implementation 00213 { 00214 template <typename T> 00215 class HasStlPairMemberTypes 00216 { 00217 typedef char Yes[1]; 00218 typedef char No [2]; 00219 00220 //detect presence of member type names 00221 template <typename U> class HelperTp {}; 00222 00223 template <class U> static Yes& hasMemberFirstType(HelperTp<typename U::first_type>*); 00224 template <class U> static No& hasMemberFirstType(...); 00225 00226 template <class U> static Yes& hasMemberSecondType(HelperTp<typename U::second_type>*); 00227 template <class U> static No& hasMemberSecondType(...); 00228 00229 public: 00230 enum { Result = sizeof(hasMemberFirstType <T>(NULL)) == sizeof(Yes) && 00231 sizeof(hasMemberSecondType<T>(NULL)) == sizeof(Yes) 00232 }; 00233 }; 00234 00235 00236 template <typename T, bool isClassType> 00237 class HasStlPairMemberVar 00238 { 00239 public: 00240 enum { Result = false}; 00241 }; 00242 00243 00244 template <typename T> 00245 class HasStlPairMemberVar<T, true> //T must be class-type! 00246 { 00247 typedef char Yes[1]; 00248 typedef char No [2]; 00249 00250 //detect presence of member variables (within T or one of it's base classes) 00251 template <typename U, U t> class HelperFn {}; 00252 00253 struct Fallback 00254 { 00255 int first; 00256 int second; 00257 }; 00258 00259 template <class U> 00260 struct Helper2 : public U, public Fallback {}; //U must be a class-type! 00261 00262 //we don't know the exact declaration of the member attribute (may be in base class), but we know what NOT to expect: 00263 template <class U> static No& hasMemberFirst(HelperFn<int Fallback::*, &Helper2<U>::first>*); 00264 template <class U> static Yes& hasMemberFirst(...); 00265 00266 template <class U> static No& hasMemberSecond(HelperFn<int Fallback::*, &Helper2<U>::second>*); 00267 template <class U> static Yes& hasMemberSecond(...); 00268 00269 public: 00270 enum { Result = sizeof(hasMemberFirst <T>(NULL)) == sizeof(Yes) && 00271 sizeof(hasMemberSecond<T>(NULL)) == sizeof(Yes) 00272 }; 00273 }; 00274 } 00275 00276 00277 template <typename T> 00278 class IsStlPair 00279 { 00280 public: 00281 enum { Result = implementation::HasStlPairMemberVar<T, implementation::HasStlPairMemberTypes<T>::Result>::Result }; 00282 }; 00283 //###################################################################################### 00284 00285 //Conversion from arbitrary types to text (for use with XML elements and attributes) 00286 enum TextType 00287 { 00288 TEXT_TYPE_BOOL, 00289 TEXT_TYPE_NUMBER, 00290 TEXT_TYPE_STRING, 00291 TEXT_TYPE_OTHER, 00292 }; 00293 00294 00295 template <class T> 00296 struct GetTextType 00297 { 00298 static const TextType value = Loki::IsSameType<T, bool>::value ? TEXT_TYPE_BOOL : 00299 StringTraits<T>::isStringLike ? TEXT_TYPE_STRING : //string before number to correctly handle char/wchar_t 00300 Loki::TypeTraits<T>::isArith ? TEXT_TYPE_NUMBER : // 00301 TEXT_TYPE_OTHER; 00302 }; 00303 00304 00305 template <class T, TextType type> 00306 struct ConvertText; 00307 /* -> expected interface 00308 { 00309 void writeText(const T& value, std::string& output) const; 00310 bool readText(const std::string& input, T& value) const; 00311 }; 00312 */ 00313 00314 //partial specialization: type bool 00315 template <class T> 00316 struct ConvertText<T, TEXT_TYPE_BOOL> 00317 { 00318 void writeText(bool value, std::string& output) const 00319 { 00320 output = value ? "true" : "false"; 00321 } 00322 bool readText(const std::string& input, bool& value) const 00323 { 00324 std::string tmp = input; 00325 zen::trim(tmp); 00326 if (tmp == "true") 00327 value = true; 00328 else if (tmp == "false") 00329 value = false; 00330 else 00331 return false; 00332 return true; 00333 } 00334 }; 00335 00336 //partial specialization: handle conversion for all built-in arithmetic types! 00337 template <class T> 00338 struct ConvertText<T, TEXT_TYPE_NUMBER> 00339 { 00340 void writeText(const T& value, std::string& output) const 00341 { 00342 output = toString<std::string>(value); 00343 } 00344 bool readText(const std::string& input, T& value) const 00345 { 00346 value = toNumber<T>(input); 00347 return true; 00348 } 00349 }; 00350 00351 //partial specialization: handle conversion for all string-like types! 00352 template <class T> 00353 struct ConvertText<T, TEXT_TYPE_STRING> 00354 { 00355 void writeText(const T& value, std::string& output) const 00356 { 00357 output = utf8CvrtTo<std::string>(value); 00358 } 00359 bool readText(const std::string& input, T& value) const 00360 { 00361 value = utf8CvrtTo<T>(input); 00362 return true; 00363 } 00364 }; 00365 00366 00367 //partial specialization: unknown type 00368 template <class T> 00369 struct ConvertText<T, TEXT_TYPE_OTHER> 00370 { 00371 //########################################################################################################################################### 00372 assert_static(sizeof(T) == -1); 00373 /* 00374 ATTENTION: The data type T is yet unknown to the zenXML framework! 00375 00376 Please provide a specialization for T of the following two functions in order to handle conversions to XML elements and attributes 00377 00378 template <> void zen::writeText(const T& value, std::string& output) 00379 template <> bool zen::readText(const std::string& input, T& value) 00380 00381 If T is structured and cannot be converted to a text representation specialize these two functions to allow at least for conversions to XML elements: 00382 00383 template <> void zen::writeValue(const T& value, XmlElement& output) 00384 template <> bool zen::readValue(const XmlElement& input, T& value) 00385 */ 00386 //########################################################################################################################################### 00387 }; 00388 00389 00390 template <class T> inline 00391 void writeText(const T& value, std::string& output) 00392 { 00393 ConvertText<T, GetTextType<T>::value>().writeText(value, output); 00394 } 00395 00396 00397 template <class T> inline 00398 bool readText(const std::string& input, T& value) 00399 { 00400 return ConvertText<T, GetTextType<T>::value>().readText(input, value); 00401 } 00402 //###################################################################################### 00403 00404 //Conversion from arbitrary types to an XML element 00405 enum ValueType 00406 { 00407 VALUE_TYPE_STL_CONTAINER, 00408 VALUE_TYPE_STL_PAIR, 00409 VALUE_TYPE_OTHER, 00410 }; 00411 00412 template <class T> 00413 struct GetValueType 00414 { 00415 static const ValueType value = GetTextType<T>::value != TEXT_TYPE_OTHER ? VALUE_TYPE_OTHER : //some string classes are also STL containers, so check this first 00416 IsStlContainer<T>::Result ? VALUE_TYPE_STL_CONTAINER : 00417 IsStlPair<T>::Result ? VALUE_TYPE_STL_PAIR : 00418 VALUE_TYPE_OTHER; 00419 }; 00420 00421 00422 template <class T, ValueType type> 00423 struct ConvertElement; 00424 /* -> expected interface 00425 { 00426 void writeValue(const T& value, XmlElement& output) const; 00427 bool readValue(const XmlElement& input, T& value) const; 00428 }; 00429 */ 00430 00431 00432 //partial specialization: handle conversion for all STL-container types! 00433 template <class T> 00434 struct ConvertElement<T, VALUE_TYPE_STL_CONTAINER> 00435 { 00436 void writeValue(const T& value, XmlElement& output) const 00437 { 00438 std::for_each(value.begin(), value.end(), 00439 [&](const typename T::value_type & childVal) 00440 { 00441 XmlElement& newChild = output.addChild("Item"); 00442 zen::writeValue(childVal, newChild); 00443 }); 00444 } 00445 bool readValue(const XmlElement& input, T& value) const 00446 { 00447 bool success = true; 00448 value.clear(); 00449 00450 auto iterPair = input.getChildren("Item"); 00451 for (auto iter = iterPair.first; iter != iterPair.second; ++iter) 00452 { 00453 typename T::value_type childVal; //MSVC 2010 bug: cannot put this into a lambda body 00454 if (zen::readValue(*iter, childVal)) 00455 value.insert(value.end(), childVal); 00456 else 00457 success = false; 00458 } 00459 return success; 00460 } 00461 }; 00462 00463 00464 //partial specialization: handle conversion for std::pair 00465 template <class T> 00466 struct ConvertElement<T, VALUE_TYPE_STL_PAIR> 00467 { 00468 void writeValue(const T& value, XmlElement& output) const 00469 { 00470 XmlElement& child1 = output.addChild("1st"); 00471 zen::writeValue(value.first, child1); 00472 00473 XmlElement& child2 = output.addChild("2nd"); 00474 zen::writeValue(value.second, child2); 00475 } 00476 bool readValue(const XmlElement& input, T& value) const 00477 { 00478 bool success = true; 00479 const XmlElement* child1 = input.getChild("1st"); 00480 if (!child1 || !zen::readValue(*child1, value.first)) 00481 success = false; 00482 00483 const XmlElement* child2 = input.getChild("2nd"); 00484 if (!child2 || !zen::readValue(*child2, value.second)) 00485 success = false; 00486 00487 return success; 00488 } 00489 }; 00490 00491 00492 //partial specialization: not a pure structured type, try text conversion (thereby respect user specializations of writeText()/readText()) 00493 template <class T> 00494 struct ConvertElement<T, VALUE_TYPE_OTHER> 00495 { 00496 void writeValue(const T& value, XmlElement& output) const 00497 { 00498 std::string tmp; 00499 writeText(value, tmp); 00500 output.setValue(tmp); 00501 } 00502 bool readValue(const XmlElement& input, T& value) const 00503 { 00504 std::string rawStr; 00505 input.getValue(rawStr); 00506 return readText(rawStr, value); 00507 } 00508 }; 00509 00510 00511 template <class T> inline 00512 void writeValue(const T& value, XmlElement& output) 00513 { 00514 ConvertElement<T, GetValueType<T>::value>().writeValue(value, output); 00515 } 00516 00517 00518 template <class T> inline 00519 bool readValue(const XmlElement& input, T& value) 00520 { 00521 return ConvertElement<T, GetValueType<T>::value>().readValue(input, value); 00522 } 00523 } 00524 00525 #endif //ZEN_XML_CONVERT_HEADER_018727409908342709743