zenXML
Straightforward C++ XML Processing
zenxml_cvrt.h
Go to the documentation of this file.
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 |    |  |  stdStringTo/toStdString - 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 = toStdString(value);
00358     }
00359     bool readText(const std::string& input, T& value) const
00360     {
00361         value = stdStringTo<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
 All Classes Namespaces Files Functions Variables