start of xml::Optional
This commit is contained in:
		
							
								
								
									
										11
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README
									
									
									
									
									
								
							| @@ -3,14 +3,19 @@ This is a C++ class for reading and writing XML structures. | |||||||
| All informaton can be found in the generated doxygen project documentation. | All informaton can be found in the generated doxygen project documentation. | ||||||
|  |  | ||||||
| Rationale: The initial idea was to map C++ data structures to XML | Rationale: The initial idea was to map C++ data structures to XML | ||||||
| files for configuration files that can easily be edited by hand. This | files for configuration files that can easily be edited by hand. | ||||||
| library does not need any kind of C++ code parser or special pre |  | ||||||
|  | This library does not need any kind of C++ code parser or special pre | ||||||
| compiler. You can specify a schema entirly in native C++. The schema | compiler. You can specify a schema entirly in native C++. The schema | ||||||
| is verified when XML is read and exceptions are thrown when the XML to | is verified when XML is read and exceptions are thrown when the XML to | ||||||
| be pares is invalid. Exceptions specify exactly the location and | be parse is invalid. Exceptions specify exactly the location and | ||||||
| reason of the problem, so that the editor of the XML file can easily | reason of the problem, so that the editor of the XML file can easily | ||||||
| find and correct the problem. | find and correct the problem. | ||||||
|  |  | ||||||
|  | C++ classes can inherit xml::Serialize and become serializable this | ||||||
|  | way. All you need to do is to overwrite one single method, where you | ||||||
|  | declare XML tag names for the class name and for all members. | ||||||
|  |  | ||||||
| (More rationale: See also "related Pages" in the doxygen project documentation) | (More rationale: See also "related Pages" in the doxygen project documentation) | ||||||
|  |  | ||||||
| Structure of the files: | Structure of the files: | ||||||
|   | |||||||
							
								
								
									
										240
									
								
								doc/doxyfile.in
									
									
									
									
									
								
							
							
						
						
									
										240
									
								
								doc/doxyfile.in
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| # Doxyfile 1.5.5 | # Doxyfile 1.5.8 | ||||||
|  |  | ||||||
| # This file describes the settings to be used by the documentation system | # This file describes the settings to be used by the documentation system | ||||||
| # doxygen (www.doxygen.org) for a project | # doxygen (www.doxygen.org) for a project | ||||||
| @@ -57,8 +57,8 @@ CREATE_SUBDIRS         = NO | |||||||
| # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,  | # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,  | ||||||
| # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),  | # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),  | ||||||
| # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,  | # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,  | ||||||
| # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,  | # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,  | ||||||
| # and Ukrainian. | # Spanish, Swedish, and Ukrainian. | ||||||
|  |  | ||||||
| OUTPUT_LANGUAGE        = English | OUTPUT_LANGUAGE        = English | ||||||
|  |  | ||||||
| @@ -155,13 +155,6 @@ QT_AUTOBRIEF           = NO | |||||||
|  |  | ||||||
| MULTILINE_CPP_IS_BRIEF = YES | MULTILINE_CPP_IS_BRIEF = YES | ||||||
|  |  | ||||||
| # If the DETAILS_AT_TOP tag is set to YES then Doxygen  |  | ||||||
| # will output the detailed description near the top, like JavaDoc. |  | ||||||
| # If set to NO, the detailed description appears after the member  |  | ||||||
| # documentation. |  | ||||||
|  |  | ||||||
| DETAILS_AT_TOP         = YES |  | ||||||
|  |  | ||||||
| # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented  | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented  | ||||||
| # member inherits the documentation from any documented member that it  | # member inherits the documentation from any documented member that it  | ||||||
| # re-implements. | # re-implements. | ||||||
| @@ -219,6 +212,17 @@ OPTIMIZE_FOR_FORTRAN   = NO | |||||||
|  |  | ||||||
| OPTIMIZE_OUTPUT_VHDL   = NO | OPTIMIZE_OUTPUT_VHDL   = NO | ||||||
|  |  | ||||||
|  | # Doxygen selects the parser to use depending on the extension of the files it parses.  | ||||||
|  | # With this tag you can assign which parser to use for a given extension.  | ||||||
|  | # Doxygen has a built-in mapping, but you can override or extend it using this tag.  | ||||||
|  | # The format is ext=language, where ext is a file extension, and language is one of  | ||||||
|  | # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,  | ||||||
|  | # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat  | ||||||
|  | # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),  | ||||||
|  | # use: inc=Fortran f=C | ||||||
|  |  | ||||||
|  | EXTENSION_MAPPING      =  | ||||||
|  |  | ||||||
| # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want  | # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want  | ||||||
| # to include (a tag file for) the STL sources as input, then you should  | # to include (a tag file for) the STL sources as input, then you should  | ||||||
| # set this tag to YES in order to let doxygen match functions declarations and  | # set this tag to YES in order to let doxygen match functions declarations and  | ||||||
| @@ -226,7 +230,7 @@ OPTIMIZE_OUTPUT_VHDL   = NO | |||||||
| # func(std::string) {}). This also make the inheritance and collaboration  | # func(std::string) {}). This also make the inheritance and collaboration  | ||||||
| # diagrams that involve STL classes more complete and accurate. | # diagrams that involve STL classes more complete and accurate. | ||||||
|  |  | ||||||
| BUILTIN_STL_SUPPORT    = NO | BUILTIN_STL_SUPPORT    = YES | ||||||
|  |  | ||||||
| # If you use Microsoft's C++/CLI language, you should set this option to YES to  | # If you use Microsoft's C++/CLI language, you should set this option to YES to  | ||||||
| # enable parsing support. | # enable parsing support. | ||||||
| @@ -239,6 +243,15 @@ CPP_CLI_SUPPORT        = NO | |||||||
|  |  | ||||||
| SIP_SUPPORT            = NO | SIP_SUPPORT            = NO | ||||||
|  |  | ||||||
|  | # For Microsoft's IDL there are propget and propput attributes to indicate getter  | ||||||
|  | # and setter methods for a property. Setting this option to YES (the default)  | ||||||
|  | # will make doxygen to replace the get and set methods by a property in the  | ||||||
|  | # documentation. This will only work if the methods are indeed getting or  | ||||||
|  | # setting a simple type. If this is not the case, or you want to show the  | ||||||
|  | # methods anyway, you should set this option to NO. | ||||||
|  |  | ||||||
|  | IDL_PROPERTY_SUPPORT   = YES | ||||||
|  |  | ||||||
| # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC  | # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC  | ||||||
| # tag is set to YES, then doxygen will reuse the documentation of the first  | # tag is set to YES, then doxygen will reuse the documentation of the first  | ||||||
| # member in the group (if any) for the other members of the group. By default  | # member in the group (if any) for the other members of the group. By default  | ||||||
| @@ -264,6 +277,22 @@ SUBGROUPING            = YES | |||||||
|  |  | ||||||
| TYPEDEF_HIDES_STRUCT   = NO | TYPEDEF_HIDES_STRUCT   = NO | ||||||
|  |  | ||||||
|  | # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to  | ||||||
|  | # determine which symbols to keep in memory and which to flush to disk.  | ||||||
|  | # When the cache is full, less often used symbols will be written to disk.  | ||||||
|  | # For small to medium size projects (<1000 input files) the default value is  | ||||||
|  | # probably good enough. For larger projects a too small cache size can cause  | ||||||
|  | # doxygen to be busy swapping symbols to and from disk most of the time  | ||||||
|  | # causing a significant performance penality.  | ||||||
|  | # If the system has enough physical memory increasing the cache will improve the  | ||||||
|  | # performance by keeping more symbols in memory. Note that the value works on  | ||||||
|  | # a logarithmic scale so increasing the size by one will rougly double the  | ||||||
|  | # memory usage. The cache size is given by this formula:  | ||||||
|  | # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,  | ||||||
|  | # corresponding to a cache size of 2^16 = 65536 symbols | ||||||
|  |  | ||||||
|  | SYMBOL_CACHE_SIZE      = 0 | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| # Build related configuration options | # Build related configuration options | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| @@ -340,7 +369,7 @@ HIDE_IN_BODY_DOCS      = NO | |||||||
| # to NO (the default) then the documentation will be excluded.  | # to NO (the default) then the documentation will be excluded.  | ||||||
| # Set it to YES to include the internal documentation. | # Set it to YES to include the internal documentation. | ||||||
|  |  | ||||||
| INTERNAL_DOCS          = NO | INTERNAL_DOCS          = YES | ||||||
|  |  | ||||||
| # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate  | # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate  | ||||||
| # file names in lower-case letters. If set to YES upper-case letters are also  | # file names in lower-case letters. If set to YES upper-case letters are also  | ||||||
| @@ -448,6 +477,19 @@ SHOW_USED_FILES        = YES | |||||||
|  |  | ||||||
| SHOW_DIRECTORIES       = NO | SHOW_DIRECTORIES       = NO | ||||||
|  |  | ||||||
|  | # Set the SHOW_FILES tag to NO to disable the generation of the Files page.  | ||||||
|  | # This will remove the Files entry from the Quick Index and from the  | ||||||
|  | # Folder Tree View (if specified). The default is YES. | ||||||
|  |  | ||||||
|  | SHOW_FILES             = YES | ||||||
|  |  | ||||||
|  | # Set the SHOW_NAMESPACES tag to NO to disable the generation of the  | ||||||
|  | # Namespaces page.  | ||||||
|  | # This will remove the Namespaces entry from the Quick Index  | ||||||
|  | # and from the Folder Tree View (if specified). The default is YES. | ||||||
|  |  | ||||||
|  | SHOW_NAMESPACES        = YES | ||||||
|  |  | ||||||
| # The FILE_VERSION_FILTER tag can be used to specify a program or script that  | # The FILE_VERSION_FILTER tag can be used to specify a program or script that  | ||||||
| # doxygen should invoke to get the current version for each file (typically from  | # doxygen should invoke to get the current version for each file (typically from  | ||||||
| # the version control system). Doxygen will invoke the program by executing (via  | # the version control system). Doxygen will invoke the program by executing (via  | ||||||
| @@ -458,6 +500,15 @@ SHOW_DIRECTORIES       = NO | |||||||
|  |  | ||||||
| FILE_VERSION_FILTER    =  | FILE_VERSION_FILTER    =  | ||||||
|  |  | ||||||
|  | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by  | ||||||
|  | # doxygen. The layout file controls the global structure of the generated output files  | ||||||
|  | # in an output format independent way. The create the layout file that represents  | ||||||
|  | # doxygen's defaults, run doxygen with the -l option. You can optionally specify a  | ||||||
|  | # file name after the option, if omitted DoxygenLayout.xml will be used as the name  | ||||||
|  | # of the layout file. | ||||||
|  |  | ||||||
|  | LAYOUT_FILE            =  | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| # configuration options related to warning and progress messages | # configuration options related to warning and progress messages | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| @@ -605,14 +656,17 @@ IMAGE_PATH             = | |||||||
| # by executing (via popen()) the command <filter> <input-file>, where <filter>  | # by executing (via popen()) the command <filter> <input-file>, where <filter>  | ||||||
| # is the value of the INPUT_FILTER tag, and <input-file> is the name of an  | # is the value of the INPUT_FILTER tag, and <input-file> is the name of an  | ||||||
| # input file. Doxygen will then use the output that the filter program writes  | # input file. Doxygen will then use the output that the filter program writes  | ||||||
| # to standard output.  If FILTER_PATTERNS is specified, this tag will be  | # to standard output.  | ||||||
|  | # If FILTER_PATTERNS is specified, this tag will be  | ||||||
| # ignored. | # ignored. | ||||||
|  |  | ||||||
| INPUT_FILTER           =  | INPUT_FILTER           =  | ||||||
|  |  | ||||||
| # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern  | # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern  | ||||||
| # basis.  Doxygen will compare the file name with each pattern and apply the  | # basis.  | ||||||
| # filter if there is a match.  The filters are a list of the form:  | # Doxygen will compare the file name with each pattern and apply the  | ||||||
|  | # filter if there is a match.  | ||||||
|  | # The filters are a list of the form:  | ||||||
| # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further  | # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further  | ||||||
| # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER  | # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER  | ||||||
| # is applied to all files. | # is applied to all files. | ||||||
| @@ -647,13 +701,13 @@ INLINE_SOURCES         = NO | |||||||
|  |  | ||||||
| STRIP_CODE_COMMENTS    = NO | STRIP_CODE_COMMENTS    = NO | ||||||
|  |  | ||||||
| # If the REFERENCED_BY_RELATION tag is set to YES (the default)  | # If the REFERENCED_BY_RELATION tag is set to YES  | ||||||
| # then for each documented function all documented  | # then for each documented function all documented  | ||||||
| # functions referencing it will be listed. | # functions referencing it will be listed. | ||||||
|  |  | ||||||
| REFERENCED_BY_RELATION = YES | REFERENCED_BY_RELATION = YES | ||||||
|  |  | ||||||
| # If the REFERENCES_RELATION tag is set to YES (the default)  | # If the REFERENCES_RELATION tag is set to YES  | ||||||
| # then for each documented function all documented entities  | # then for each documented function all documented entities  | ||||||
| # called/used by that function will be listed. | # called/used by that function will be listed. | ||||||
|  |  | ||||||
| @@ -662,7 +716,8 @@ REFERENCES_RELATION    = YES | |||||||
| # If the REFERENCES_LINK_SOURCE tag is set to YES (the default)  | # If the REFERENCES_LINK_SOURCE tag is set to YES (the default)  | ||||||
| # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from  | # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from  | ||||||
| # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will  | # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will  | ||||||
| # link to the source code.  Otherwise they will link to the documentstion. | # link to the source code.  | ||||||
|  | # Otherwise they will link to the documentation. | ||||||
|  |  | ||||||
| REFERENCES_LINK_SOURCE = YES | REFERENCES_LINK_SOURCE = YES | ||||||
|  |  | ||||||
| @@ -751,12 +806,13 @@ HTML_STYLESHEET        = | |||||||
|  |  | ||||||
| HTML_ALIGN_MEMBERS     = YES | HTML_ALIGN_MEMBERS     = YES | ||||||
|  |  | ||||||
| # If the GENERATE_HTMLHELP tag is set to YES, additional index files  | # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML  | ||||||
| # will be generated that can be used as input for tools like the  | # documentation will contain sections that can be hidden and shown after the  | ||||||
| # Microsoft HTML help workshop to generate a compiled HTML help file (.chm)  | # page has loaded. For this to work a browser that supports  | ||||||
| # of the generated HTML documentation. | # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox  | ||||||
|  | # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). | ||||||
|  |  | ||||||
| GENERATE_HTMLHELP      = NO | HTML_DYNAMIC_SECTIONS  = YES | ||||||
|  |  | ||||||
| # If the GENERATE_DOCSET tag is set to YES, additional index files  | # If the GENERATE_DOCSET tag is set to YES, additional index files  | ||||||
| # will be generated that can be used as input for Apple's Xcode 3  | # will be generated that can be used as input for Apple's Xcode 3  | ||||||
| @@ -766,6 +822,7 @@ GENERATE_HTMLHELP      = NO | |||||||
| # directory and running "make install" will install the docset in  | # directory and running "make install" will install the docset in  | ||||||
| # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find  | # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find  | ||||||
| # it at startup.  | # it at startup.  | ||||||
|  | # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. | ||||||
|  |  | ||||||
| GENERATE_DOCSET        = NO | GENERATE_DOCSET        = NO | ||||||
|  |  | ||||||
| @@ -783,13 +840,12 @@ DOCSET_FEEDNAME        = "Doxygen generated docs" | |||||||
|  |  | ||||||
| DOCSET_BUNDLE_ID       = org.doxygen.Project | DOCSET_BUNDLE_ID       = org.doxygen.Project | ||||||
|  |  | ||||||
| # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML  | # If the GENERATE_HTMLHELP tag is set to YES, additional index files  | ||||||
| # documentation will contain sections that can be hidden and shown after the  | # will be generated that can be used as input for tools like the  | ||||||
| # page has loaded. For this to work a browser that supports  | # Microsoft HTML help workshop to generate a compiled HTML help file (.chm)  | ||||||
| # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox  | # of the generated HTML documentation. | ||||||
| # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). |  | ||||||
|  |  | ||||||
| HTML_DYNAMIC_SECTIONS  = NO | GENERATE_HTMLHELP      = NO | ||||||
|  |  | ||||||
| # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can  | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can  | ||||||
| # be used to specify the file name of the resulting .chm file. You  | # be used to specify the file name of the resulting .chm file. You  | ||||||
| @@ -811,6 +867,12 @@ HHC_LOCATION           = | |||||||
|  |  | ||||||
| GENERATE_CHI           = NO | GENERATE_CHI           = NO | ||||||
|  |  | ||||||
|  | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING  | ||||||
|  | # is used to encode HtmlHelp index (hhk), content (hhc) and project file  | ||||||
|  | # content. | ||||||
|  |  | ||||||
|  | CHM_INDEX_ENCODING     =  | ||||||
|  |  | ||||||
| # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag  | # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag  | ||||||
| # controls whether a binary table of contents is generated (YES) or a  | # controls whether a binary table of contents is generated (YES) or a  | ||||||
| # normal table of contents (NO) in the .chm file. | # normal table of contents (NO) in the .chm file. | ||||||
| @@ -822,6 +884,55 @@ BINARY_TOC             = NO | |||||||
|  |  | ||||||
| TOC_EXPAND             = NO | TOC_EXPAND             = NO | ||||||
|  |  | ||||||
|  | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER  | ||||||
|  | # are set, an additional index file will be generated that can be used as input for  | ||||||
|  | # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated  | ||||||
|  | # HTML documentation. | ||||||
|  |  | ||||||
|  | GENERATE_QHP           = NO | ||||||
|  |  | ||||||
|  | # If the QHG_LOCATION tag is specified, the QCH_FILE tag can  | ||||||
|  | # be used to specify the file name of the resulting .qch file.  | ||||||
|  | # The path specified is relative to the HTML output folder. | ||||||
|  |  | ||||||
|  | QCH_FILE               =  | ||||||
|  |  | ||||||
|  | # The QHP_NAMESPACE tag specifies the namespace to use when generating  | ||||||
|  | # Qt Help Project output. For more information please see  | ||||||
|  | # http://doc.trolltech.com/qthelpproject.html#namespace | ||||||
|  |  | ||||||
|  | QHP_NAMESPACE          =  | ||||||
|  |  | ||||||
|  | # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating  | ||||||
|  | # Qt Help Project output. For more information please see  | ||||||
|  | # http://doc.trolltech.com/qthelpproject.html#virtual-folders | ||||||
|  |  | ||||||
|  | QHP_VIRTUAL_FOLDER     = doc | ||||||
|  |  | ||||||
|  | # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.  | ||||||
|  | # For more information please see  | ||||||
|  | # http://doc.trolltech.com/qthelpproject.html#custom-filters | ||||||
|  |  | ||||||
|  | QHP_CUST_FILTER_NAME   =  | ||||||
|  |  | ||||||
|  | # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see  | ||||||
|  | # <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. | ||||||
|  |  | ||||||
|  | QHP_CUST_FILTER_ATTRS  =  | ||||||
|  |  | ||||||
|  | # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's  | ||||||
|  | # filter section matches.  | ||||||
|  | # <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. | ||||||
|  |  | ||||||
|  | QHP_SECT_FILTER_ATTRS  =  | ||||||
|  |  | ||||||
|  | # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can  | ||||||
|  | # be used to specify the location of Qt's qhelpgenerator.  | ||||||
|  | # If non-empty doxygen will try to run qhelpgenerator on the generated  | ||||||
|  | # .qhp file. | ||||||
|  |  | ||||||
|  | QHG_LOCATION           =  | ||||||
|  |  | ||||||
| # The DISABLE_INDEX tag can be used to turn on/off the condensed index at  | # The DISABLE_INDEX tag can be used to turn on/off the condensed index at  | ||||||
| # top of each HTML page. The value NO (the default) enables the index and  | # top of each HTML page. The value NO (the default) enables the index and  | ||||||
| # the value YES disables it. | # the value YES disables it. | ||||||
| @@ -833,14 +944,22 @@ DISABLE_INDEX          = NO | |||||||
|  |  | ||||||
| ENUM_VALUES_PER_LINE   = 4 | ENUM_VALUES_PER_LINE   = 4 | ||||||
|  |  | ||||||
| # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index  | ||||||
| # generated containing a tree-like index structure (just like the one that  | # structure should be generated to display hierarchical information.  | ||||||
|  | # If the tag value is set to FRAME, a side panel will be generated  | ||||||
|  | # containing a tree-like index structure (just like the one that  | ||||||
| # is generated for HTML Help). For this to work a browser that supports  | # is generated for HTML Help). For this to work a browser that supports  | ||||||
| # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,  | # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,  | ||||||
| # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are  | # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are  | ||||||
| # probably better off using the HTML help feature. | # probably better off using the HTML help feature. Other possible values  | ||||||
|  | # for this tag are: HIERARCHIES, which will generate the Groups, Directories,  | ||||||
|  | # and Class Hierarchy pages using a tree view instead of an ordered list;  | ||||||
|  | # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which  | ||||||
|  | # disables this behavior completely. For backwards compatibility with previous  | ||||||
|  | # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE  | ||||||
|  | # respectively. | ||||||
|  |  | ||||||
| GENERATE_TREEVIEW      = NO | GENERATE_TREEVIEW      = YES | ||||||
|  |  | ||||||
| # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be  | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be  | ||||||
| # used to set the initial width (in pixels) of the frame in which the tree  | # used to set the initial width (in pixels) of the frame in which the tree  | ||||||
| @@ -848,6 +967,14 @@ GENERATE_TREEVIEW      = NO | |||||||
|  |  | ||||||
| TREEVIEW_WIDTH         = 250 | TREEVIEW_WIDTH         = 250 | ||||||
|  |  | ||||||
|  | # Use this tag to change the font size of Latex formulas included  | ||||||
|  | # as images in the HTML documentation. The default is 10. Note that  | ||||||
|  | # when you change the font size after a successful doxygen run you need  | ||||||
|  | # to manually remove any form_*.png images from the HTML output directory  | ||||||
|  | # to force them to be regenerated. | ||||||
|  |  | ||||||
|  | FORMULA_FONTSIZE       = 10 | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| # configuration options related to the LaTeX output | # configuration options related to the LaTeX output | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| @@ -1060,8 +1187,10 @@ GENERATE_PERLMOD       = NO | |||||||
| PERLMOD_LATEX          = NO | PERLMOD_LATEX          = NO | ||||||
|  |  | ||||||
| # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be  | # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be  | ||||||
| # nicely formatted so it can be parsed by a human reader.  This is useful  | # nicely formatted so it can be parsed by a human reader.  | ||||||
| # if you want to understand what is going on.  On the other hand, if this  | # This is useful  | ||||||
|  | # if you want to understand what is going on.  | ||||||
|  | # On the other hand, if this  | ||||||
| # tag is set to NO the size of the Perl module output will be much smaller  | # tag is set to NO the size of the Perl module output will be much smaller  | ||||||
| # and Perl will parse it just the same. | # and Perl will parse it just the same. | ||||||
|  |  | ||||||
| @@ -1148,9 +1277,11 @@ SKIP_FUNCTION_MACROS   = YES | |||||||
| # Optionally an initial location of the external documentation  | # Optionally an initial location of the external documentation  | ||||||
| # can be added for each tagfile. The format of a tag file without  | # can be added for each tagfile. The format of a tag file without  | ||||||
| # this location is as follows:  | # this location is as follows:  | ||||||
| #   TAGFILES = file1 file2 ...  | #   | ||||||
|  | # TAGFILES = file1 file2 ...  | ||||||
| # Adding location for the tag files is done as follows:  | # Adding location for the tag files is done as follows:  | ||||||
| #   TAGFILES = file1=loc1 "file2 = loc2" ...  | #   | ||||||
|  | # TAGFILES = file1=loc1 "file2 = loc2" ...  | ||||||
| # where "loc1" and "loc2" can be relative or absolute paths or  | # where "loc1" and "loc2" can be relative or absolute paths or  | ||||||
| # URLs. If a location is present for each tag, the installdox tool  | # URLs. If a location is present for each tag, the installdox tool  | ||||||
| # does not have to be run to correct the links.  | # does not have to be run to correct the links.  | ||||||
| @@ -1218,6 +1349,29 @@ HIDE_UNDOC_RELATIONS   = NO | |||||||
|  |  | ||||||
| HAVE_DOT               = @HAVE_DOT@ | HAVE_DOT               = @HAVE_DOT@ | ||||||
|  |  | ||||||
|  | # By default doxygen will write a font called FreeSans.ttf to the output  | ||||||
|  | # directory and reference it in all dot files that doxygen generates. This  | ||||||
|  | # font does not include all possible unicode characters however, so when you need  | ||||||
|  | # these (or just want a differently looking font) you can specify the font name  | ||||||
|  | # using DOT_FONTNAME. You need need to make sure dot is able to find the font,  | ||||||
|  | # which can be done by putting it in a standard location or by setting the  | ||||||
|  | # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory  | ||||||
|  | # containing the font. | ||||||
|  |  | ||||||
|  | DOT_FONTNAME           = FreeSans | ||||||
|  |  | ||||||
|  | # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.  | ||||||
|  | # The default size is 10pt. | ||||||
|  |  | ||||||
|  | DOT_FONTSIZE           = 10 | ||||||
|  |  | ||||||
|  | # By default doxygen will tell dot to use the output directory to look for the  | ||||||
|  | # FreeSans.ttf font (which doxygen will put there itself). If you specify a  | ||||||
|  | # different font using DOT_FONTNAME you can set the path where dot  | ||||||
|  | # can find it using this tag. | ||||||
|  |  | ||||||
|  | DOT_FONTPATH           =  | ||||||
|  |  | ||||||
| # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen  | # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen  | ||||||
| # will generate a graph for each documented class showing the direct and  | # will generate a graph for each documented class showing the direct and  | ||||||
| # indirect inheritance relations. Setting this tag to YES will force the  | # indirect inheritance relations. Setting this tag to YES will force the  | ||||||
| @@ -1307,7 +1461,7 @@ DOT_PATH               = | |||||||
|  |  | ||||||
| DOTFILE_DIRS           =  | DOTFILE_DIRS           =  | ||||||
|  |  | ||||||
| # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of  | # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of  | ||||||
| # nodes that will be shown in the graph. If the number of nodes in a graph  | # nodes that will be shown in the graph. If the number of nodes in a graph  | ||||||
| # becomes larger than this value, doxygen will truncate the graph, which is  | # becomes larger than this value, doxygen will truncate the graph, which is  | ||||||
| # visualized by representing a node as a red box. Note that doxygen if the  | # visualized by representing a node as a red box. Note that doxygen if the  | ||||||
| @@ -1328,10 +1482,10 @@ DOT_GRAPH_MAX_NODES    = 50 | |||||||
| MAX_DOT_GRAPH_DEPTH    = 0 | MAX_DOT_GRAPH_DEPTH    = 0 | ||||||
|  |  | ||||||
| # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent  | # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent  | ||||||
| # background. This is enabled by default, which results in a transparent  | # background. This is disabled by default, because dot on Windows does not  | ||||||
| # background. Warning: Depending on the platform used, enabling this option  | # seem to support this out of the box. Warning: Depending on the platform used,  | ||||||
| # may lead to badly anti-aliased labels on the edges of a graph (i.e. they  | # enabling this option may lead to badly anti-aliased labels on the edges of  | ||||||
| # become hard to read). | # a graph (i.e. they become hard to read). | ||||||
|  |  | ||||||
| DOT_TRANSPARENT        = YES | DOT_TRANSPARENT        = YES | ||||||
|  |  | ||||||
| @@ -1355,7 +1509,7 @@ GENERATE_LEGEND        = YES | |||||||
| DOT_CLEANUP            = YES | DOT_CLEANUP            = YES | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| # Configuration::additions related to the search engine    | # Options related to the search engine | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
|  |  | ||||||
| # The SEARCHENGINE tag specifies whether or not a search engine should be  | # The SEARCHENGINE tag specifies whether or not a search engine should be  | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| // g++ -I../../src ../../src/xml.cxx address.cxx |  | ||||||
|  |  | ||||||
| #include <xml-cxx/xml.hxx> | #include <xml-cxx/xml.hxx> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| // g++ -I../../src ../../src/xml.cxx contain_serialization.cxx |  | ||||||
|  |  | ||||||
| #include <xml-cxx/xml.hxx> | #include <xml-cxx/xml.hxx> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| // g++ -I../../src ../../src/xml.cxx inherit_serialization.cxx |  | ||||||
|  |  | ||||||
| #include <xml-cxx/xml.hxx> | #include <xml-cxx/xml.hxx> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
| @@ -23,12 +21,12 @@ class A: public xml::Serialize { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class B: public A { | class B: public A { // A inherits xml::Serialize, B inherits A | ||||||
|   public: |   public: | ||||||
|     int b; |     int b; | ||||||
|   protected: |   protected: | ||||||
|     void initXmlMembers() { |     void initXmlMembers() { | ||||||
|       A::initXmlMembers(); |       A::initXmlMembers(); // <- Here is the important difference | ||||||
|       className("B"); |       className("B"); | ||||||
|       persist(b, "b"); |       persist(b, "b"); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| // g++ -I../../src ../../src/xml.cxx list_serialization.cxx |  | ||||||
|  |  | ||||||
| #include <xml-cxx/xml.hxx> | #include <xml-cxx/xml.hxx> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
| @@ -37,26 +35,57 @@ class B: public xml::Serialize { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| int main(int, char**) { | int main(int, char**) { | ||||||
|   std::stringstream ss("<B>\n" |   std::stringstream ss("<B>" | ||||||
|                        "<b>1234</b>" |                        "    <b>1234</b>" | ||||||
|                        "<a><list><item>guguseli</item></list></a>" |                        "    <a>" | ||||||
|                        "<As>" |                        "        <list>" | ||||||
|                        "<A>\n" |                        "            <item>guguseli</item>" | ||||||
|                        "\t<list>\n" |                        "        </list>" | ||||||
|                        "\t\t<item>Hello</item>\n" |                        "    </a>" | ||||||
|                        "\t\t<item>World</item>\n" |                        "    <As>" | ||||||
|                        "\t\t<item>how</item>\n" |                        "        <A>" | ||||||
|                        "\t\t<item>are</item>\n" |                        "            <list>" | ||||||
|                        "\t\t<item>you</item>\n" |                        "                <item>Hello</item>" | ||||||
|                        "\t</list>\n" |                        "                <item>World</item>" | ||||||
|                        "</A>" |                        "                <item>how</item>" | ||||||
|                        "</As>" |                        "                <item>are</item>" | ||||||
|  |                        "                <item>you</item>" | ||||||
|  |                        "            </list>" | ||||||
|  |                        "        </A>" | ||||||
|  |                        "        <A>" | ||||||
|  |                        "            <list>" | ||||||
|  |                        "                <item>a</item>" | ||||||
|  |                        "                <item>b</item>" | ||||||
|  |                        "                <item>c</item>" | ||||||
|  |                        "                <item>d</item>" | ||||||
|  |                        "                <item>e</item>" | ||||||
|  |                        "            </list>" | ||||||
|  |                        "        </A>" | ||||||
|  |                        "        <A>" | ||||||
|  |                        "            <list>" | ||||||
|  |                        "                <item>f</item>" | ||||||
|  |                        "                <item>g</item>" | ||||||
|  |                        "                <item>h</item>" | ||||||
|  |                        "                <item>i</item>" | ||||||
|  |                        "                <item>j</item>" | ||||||
|  |                        "            </list>" | ||||||
|  |                        "        </A>" | ||||||
|  |                        "        <A>" | ||||||
|  |                        "            <list>" | ||||||
|  |                        "                <item>k</item>" | ||||||
|  |                        "                <item>l</item>" | ||||||
|  |                        "                <item>m</item>" | ||||||
|  |                        "                <item>n</item>" | ||||||
|  |                        "                <item>o</item>" | ||||||
|  |                        "            </list>" | ||||||
|  |                        "        </A>" | ||||||
|  |                        "    </As>" | ||||||
|                        "</B>"); |                        "</B>"); | ||||||
|   B b; |   B b; | ||||||
|   std::cout<<"SCHEMA:"<<std::endl<<b.schema()<<std::endl; |   std::cout<<"SCHEMA:"<<std::endl<<b.schema()<<std::endl; | ||||||
|   b.loadXml(ss); |   b.loadXml(ss); | ||||||
| //   if (a.list.front()=="Hello") a.list.front()="Good Bye"; |   if (b.as.front().list.front()=="Hello") b.as.front().list.front()="Good Bye"; | ||||||
| //   if (a.list.back()=="you") a.list.back()="we"; |   if (b.as.front().list.back()=="you") b.as.front().list.back()="we"; | ||||||
|   b.saveXml(std::cout)<<std::endl; |   b.saveXml(std::cout)<<std::endl; | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| // g++ -I../../src ../../src/xml.cxx node_macros.cxx |  | ||||||
|  |  | ||||||
| #include <xml-cxx/xml.hxx> | #include <xml-cxx/xml.hxx> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| // g++ -I../../src ../../src/xml.cxx serialization.cxx |  | ||||||
|  |  | ||||||
| #include <xml-cxx/xml.hxx> | #include <xml-cxx/xml.hxx> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
|  |  | ||||||
| AM_CXXFLAGS += -I ${top_srcdir}/src | AM_CXXFLAGS += -I ${top_srcdir}/src | ||||||
| lib_LTLIBRARIES = libxml-cxx.la | lib_LTLIBRARIES = libxml-cxx.la | ||||||
| nobase_include_HEADERS = xml-cxx/xml.hxx | nobase_include_HEADERS = xml-cxx/xml.hxx xml-cxx/any.hxx | ||||||
|  |  | ||||||
| libxml_cxx_la_SOURCES = xml.cxx | libxml_cxx_la_SOURCES = xml.cxx | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,107 +19,158 @@ | |||||||
|  |  | ||||||
| namespace xml { | namespace xml { | ||||||
|  |  | ||||||
|  |   class Serialize; | ||||||
|  |  | ||||||
|  |   //! @cond INTERNAL | ||||||
|  |  | ||||||
|  |   //! @addtogroup serialization | ||||||
|  |   //@{ | ||||||
|  |  | ||||||
|  |   /*! @defgroup xmlAny (internal) Any Object with limited Polymorfism | ||||||
|  |  | ||||||
|  |       @internal The implementation of xml::Any is an adaption of @c | ||||||
|  |                 boost::any (see http://www.boost.org), but instead of | ||||||
|  |                 holding any element, but without polymorfism, the | ||||||
|  |                 implementation of xml::Any only holds basic C++ types | ||||||
|  |                 (@c int, @c long, @c float, ...), plus @c std::string | ||||||
|  |                 and xml::Serialize. All other non-standard-C++ types | ||||||
|  |                 are stored as xml::Serialize*. This way, we can get a | ||||||
|  |                 polymorfic any type, but only for children of | ||||||
|  |                 xml::Serialize, but in fact, that's all we | ||||||
|  |                 need. Another limitation is, that xml::Any only stores | ||||||
|  |                 pointer types. Simply because we don't need more. */ | ||||||
|  |   //@{ | ||||||
|  |  | ||||||
|  |   //! @internal Number of supported types that can be stored as XML. | ||||||
|  |   const int MAX_NUM(14); | ||||||
|  |  | ||||||
|  |   template<int NUM> struct ToType {typedef Serialize      Type;}; | ||||||
|  |   template<> struct ToType<1>     {typedef Serialize      Type;}; | ||||||
|  |   template<> struct ToType<2>     {typedef std::string    Type;}; | ||||||
|  |   template<> struct ToType<3>     {typedef bool           Type;}; | ||||||
|  |   template<> struct ToType<4>     {typedef unsigned char  Type;}; | ||||||
|  |   template<> struct ToType<5>     {typedef signed   char  Type;}; | ||||||
|  |   template<> struct ToType<6>     {typedef          char  Type;}; | ||||||
|  |   template<> struct ToType<7>     {typedef unsigned short Type;}; | ||||||
|  |   template<> struct ToType<8>     {typedef signed   short Type;}; | ||||||
|  |   template<> struct ToType<9>     {typedef unsigned int   Type;}; | ||||||
|  |   template<> struct ToType<10>    {typedef signed   int   Type;}; | ||||||
|  |   template<> struct ToType<11>    {typedef unsigned long  Type;}; | ||||||
|  |   template<> struct ToType<12>    {typedef signed   long  Type;}; | ||||||
|  |   template<> struct ToType<13>    {typedef float          Type;}; | ||||||
|  |   template<> struct ToType<14>    {typedef double         Type;}; | ||||||
|  |    | ||||||
|  |   template<typename T> struct ToNum       {static const int NUM = 1;}; | ||||||
|  |   template<> struct ToNum<Serialize     > {static const int NUM = 1;}; | ||||||
|  |   template<> struct ToNum<std::string   > {static const int NUM = 2;}; | ||||||
|  |   template<> struct ToNum<bool          > {static const int NUM = 3;}; | ||||||
|  |   template<> struct ToNum<unsigned char > {static const int NUM = 4;}; | ||||||
|  |   template<> struct ToNum<signed   char > {static const int NUM = 5;}; | ||||||
|  |   template<> struct ToNum<         char > {static const int NUM = 6;}; | ||||||
|  |   template<> struct ToNum<unsigned short> {static const int NUM = 7;}; | ||||||
|  |   template<> struct ToNum<signed   short> {static const int NUM = 8;}; | ||||||
|  |   template<> struct ToNum<unsigned int  > {static const int NUM = 9;}; | ||||||
|  |   template<> struct ToNum<signed   int  > {static const int NUM = 10;}; | ||||||
|  |   template<> struct ToNum<unsigned long > {static const int NUM = 11;}; | ||||||
|  |   template<> struct ToNum<signed   long > {static const int NUM = 12;}; | ||||||
|  |   template<> struct ToNum<float         > {static const int NUM = 13;}; | ||||||
|  |   template<> struct ToNum<double        > {static const int NUM = 14;}; | ||||||
|  |        | ||||||
|  |   template<typename T> bool isSerialize() { | ||||||
|  |     return ToNum<T>::NUM == 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template <typename T, bool GOOD=(ToNum<T>::NUM==1)> struct Mapper { | ||||||
|  |       static Serialize* toSerialize(T& obj) { | ||||||
|  |         return 0; | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |   template <typename T> struct Mapper<T, true> { | ||||||
|  |       static Serialize* toSerialize(T& obj) { | ||||||
|  |         return dynamic_cast<Serialize*>(&obj); | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   class Any { |   class Any { | ||||||
|        |     public: | ||||||
|     public: // structors |       Any(): _content(0) {} | ||||||
|  |       template<typename TYPE> Any(TYPE* value): | ||||||
|       Any(): content(0) {} |           _content(new Holder<TYPE>(value)) { | ||||||
|  |       } | ||||||
|       template<typename ValueType> Any(const ValueType& value): |       Any(const Any& other): | ||||||
|           content(new holder<ValueType>(value)) { |           _content(other._content?other._content->clone():0) { | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       Any(const Any& other): content(other.content?other.content->clone():0) {} |  | ||||||
|  |  | ||||||
|       ~Any() { |       ~Any() { | ||||||
|         delete content; |         delete _content; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|     public: // modifiers |  | ||||||
|  |  | ||||||
|       Any& swap(Any& rhs) { |       Any& swap(Any& rhs) { | ||||||
|         std::swap(content, rhs.content); |         std::swap(_content, rhs._content); | ||||||
|         return *this; |         return *this; | ||||||
|       } |       } | ||||||
|  |       template<typename TYPE> Any& operator=(TYPE* rhs) { | ||||||
|       template<typename ValueType> Any& operator=(const ValueType& rhs) { |  | ||||||
|         Any(rhs).swap(*this); |         Any(rhs).swap(*this); | ||||||
|         return *this; |         return *this; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       Any& operator=(const Any& rhs) { |       Any& operator=(const Any& rhs) { | ||||||
|         Any(rhs).swap(*this); |         Any(rhs).swap(*this); | ||||||
|         return *this; |         return *this; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|     public: // queries |  | ||||||
|  |  | ||||||
|       bool empty() const { |       bool empty() const { | ||||||
|         return !content; |         return !_content; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       const std::type_info& type() const { |       const std::type_info& type() const { | ||||||
|         return content?content->type():typeid(void); |         return _content?_content->type():typeid(void); | ||||||
|       } |       } | ||||||
|  |       class Placeholder { | ||||||
|     private: // types |  | ||||||
|        |  | ||||||
|       class placeholder { |  | ||||||
|         public: // structors |  | ||||||
|           virtual ~placeholder() {} |  | ||||||
|           virtual const std::type_info& type() const = 0; |  | ||||||
|           virtual placeholder* clone() const = 0; |  | ||||||
|       }; |  | ||||||
|  |  | ||||||
|       template<typename ValueType> class holder: public placeholder { |  | ||||||
|            |  | ||||||
|         public: |         public: | ||||||
|  |           virtual ~Placeholder() {} | ||||||
|           holder(const ValueType& value): held(value) {} |           virtual const std::type_info& type() const = 0; | ||||||
|  |           virtual Placeholder* clone() const = 0; | ||||||
|           virtual const std::type_info& type() const { |  | ||||||
|             return typeid(ValueType); |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           virtual placeholder* clone() const { |  | ||||||
|             return new holder(held); |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           ValueType held; |  | ||||||
|  |  | ||||||
|       }; |       }; | ||||||
|  |       template<typename TYPE> class Holder: public Placeholder { | ||||||
|     private: // representation |         public: | ||||||
|  |           Holder(typename ToType<ToNum<TYPE>::NUM>::Type* value): | ||||||
|       template<typename ValueType> friend ValueType* any_cast(Any*); |               _held(value) { | ||||||
|       template<typename ValueType> friend ValueType& any_cast(Any&); |           } | ||||||
|  |           virtual const std::type_info& type() const { | ||||||
|       placeholder* content; |             return typeid(typename ToType<ToNum<TYPE>::NUM>::Type); | ||||||
|  |           } | ||||||
|  |           virtual Placeholder* clone() const { | ||||||
|  |             return new Holder(_held); | ||||||
|  |           } | ||||||
|  |           typename ToType<ToNum<TYPE>::NUM>::Type* _held; | ||||||
|  |       }; | ||||||
|  |     private: | ||||||
|  |       template<typename TYPE> friend TYPE* any_cast(Any*); | ||||||
|  |       template<typename TYPE> friend TYPE* any_cast(Any&); | ||||||
|  |       Placeholder* _content; | ||||||
|   }; |   }; | ||||||
|  |   template<typename TYPE> TYPE* any_cast(Any* operand) { | ||||||
|   template<typename ValueType> ValueType* any_cast(Any* operand) { |     return operand && operand->type() == typeid(TYPE) | ||||||
|     return operand && operand->type() == typeid(ValueType) |       ? static_cast<Any::Holder<TYPE>*>(operand->_content)->_held | ||||||
|       ? &static_cast<Any::holder<ValueType>*>(operand->content)->held |  | ||||||
|       : 0; |       : 0; | ||||||
|   } |   } | ||||||
|  |   template<typename TYPE> const TYPE* any_cast(const Any* operand) { | ||||||
|   template<typename ValueType> const ValueType* any_cast(const Any* operand) { |     return any_cast<TYPE>(const_cast<Any*>(operand)); | ||||||
|     return any_cast<ValueType>(const_cast<Any*>(operand)); |  | ||||||
|   } |   } | ||||||
|  |   template<typename TYPE> TYPE* any_cast(Any& operand) { | ||||||
|   template<typename ValueType> ValueType& any_cast(Any& operand) { |     if (operand.type()==typeid(TYPE)) | ||||||
|     if (operand.type()==typeid(ValueType)) |       return static_cast<Any::Holder<TYPE>*>(operand._content)->_held; | ||||||
|       return static_cast<Any::holder<ValueType>*>(operand.content)->held; |  | ||||||
|     throw std::bad_cast(); |     throw std::bad_cast(); | ||||||
|   } |   } | ||||||
|  |   template<typename TYPE> const TYPE* any_cast(const Any& operand) { | ||||||
|   template<typename ValueType> const ValueType& any_cast(const Any& operand) { |     return any_cast<TYPE>(const_cast<Any&>(operand)); | ||||||
|     return any_cast<ValueType>(const_cast<Any&>(operand)); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   //@} | ||||||
|  |   //@} | ||||||
|  |  | ||||||
|  |   //! @endcond INTERNAL | ||||||
|  |    | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Note for this file only (this file is in large parts taken from boost): | ||||||
|  |  | ||||||
| // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. | // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. | ||||||
| // | // | ||||||
| // Distributed under the Boost Software License, Version 1.0. (See | // Distributed under the Boost Software License, Version 1.0. (See | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ | |||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <list> |  | ||||||
| #include <set> | #include <set> | ||||||
| #include <map> | #include <map> | ||||||
| #include <memory> | #include <memory> | ||||||
| @@ -20,6 +19,7 @@ | |||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <xml-cxx/any.hxx> | #include <xml-cxx/any.hxx> | ||||||
|  |  | ||||||
|  | //! @cond DEBUG | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
| @@ -51,7 +51,7 @@ class MethodTrace { | |||||||
|     }                                           \ |     }                                           \ | ||||||
|     assert(Y);                                  \ |     assert(Y);                                  \ | ||||||
| } | } | ||||||
|  | //! @endcond | ||||||
|  |  | ||||||
| /*! @mainpage | /*! @mainpage | ||||||
|  |  | ||||||
| @@ -60,11 +60,90 @@ class MethodTrace { | |||||||
|     - Specify your XML schema in C++ using common C++ syntax, |     - Specify your XML schema in C++ using common C++ syntax, | ||||||
|       such as shift, dereference, etc. |       such as shift, dereference, etc. | ||||||
|     - Verify the schema of XML files while they are read from a stream. |     - Verify the schema of XML files while they are read from a stream. | ||||||
|  |     - Map and store your own C++ classes to XML and restore them back. | ||||||
|  |  | ||||||
|  |     @section basics Basics | ||||||
|  |  | ||||||
|  |     Include file: | ||||||
|  |     @code | ||||||
|  |     #include <xml-cxx/xml.hxx> | ||||||
|  |     @endcode | ||||||
|  |  | ||||||
|  |     Link option: | ||||||
|  |     @code | ||||||
|  |     -lxml-cxx | ||||||
|  |     @endcode | ||||||
|  |  | ||||||
|  |     @section schemaFactory Factory with Schema Declaration | ||||||
|  |      | ||||||
|  |     Small example on how to declare an XML schema (@ref freexml), you | ||||||
|  |     may then use <code>template.read(is)</code> to read XML from a | ||||||
|  |     stream: | ||||||
|  |      | ||||||
|  |     @code | ||||||
|  |       // start with root element: <root id=""> | ||||||
|  |       xml::Factory template(xml::Node("root").attr("id", xml::optional) | ||||||
|  |                             // <root> contains any number of <child> | ||||||
|  |                             <<xml::String("child") | ||||||
|  |                             // must contain exactly one <other> | ||||||
|  |                             <<(xml::Node("other").limits(1, 1) | ||||||
|  |                                // <other> contains min 2 max 4 <text> | ||||||
|  |                                <<xml::String("text").limits(2, 4))); | ||||||
|  |     @endcode | ||||||
|  |  | ||||||
|  |     @section introMacro Using Macros Instead od Literal Text | ||||||
|  |  | ||||||
|  |     If you prefere using constants instead of literal texts, you can | ||||||
|  |     declare the node names before you use them (@ref xmlConst): | ||||||
|  |  | ||||||
|  |     @code | ||||||
|  |     XML_NODE(root); | ||||||
|  |     XML_STRING(child); | ||||||
|  |     [...] | ||||||
|  |     @endcode | ||||||
|  |      | ||||||
|  |     @code | ||||||
|  |     xml::Factory template(xml::node::root.clone()->attr("id", xml::optional) | ||||||
|  |                           <<*xml::string::child.clone() | ||||||
|  |                           [...] | ||||||
|  |     @endcode | ||||||
|  |  | ||||||
|  |     @section introSer Serialize Classes, Join Classes with XML | ||||||
|  |  | ||||||
|  |     When inheriting from xml::Serialize, your class inherits the | ||||||
|  |     methods xml::Serialize::loadXml and | ||||||
|  |     xml::Serialize::saveXml. Simply overwrite | ||||||
|  |     xml::Serialize::initXmlMembers to make your class serializable | ||||||
|  |     (@ref serialization): | ||||||
|  |  | ||||||
|  |     @code | ||||||
|  |     class MyClass: public xml::Serialize { | ||||||
|  |       [...] | ||||||
|  |       protected: | ||||||
|  |         void initXmlMembers() { | ||||||
|  |           className("MyClass"); | ||||||
|  |           persist(i, "i"); | ||||||
|  |           persist(s, "s"); | ||||||
|  |           persist(l, "l"); | ||||||
|  |         } | ||||||
|  |       private: | ||||||
|  |         int i; | ||||||
|  |         std::string s; | ||||||
|  |         xml::List<std::string> l; // same behaviour as std::list | ||||||
|  |     }; | ||||||
|  |     @endcode | ||||||
|  |  | ||||||
|  |     @section readme The README File | ||||||
|      |      | ||||||
|     From the README file: |  | ||||||
|     @include README |     @include README | ||||||
|  |  | ||||||
|     @page Known Limitations |     @page license License is LGPL 3 | ||||||
|  |  | ||||||
|  |     File COPYING from http://www.gnu.org/licenses/lgpl-3.0.txt: | ||||||
|  |  | ||||||
|  |     @include COPYING | ||||||
|  |  | ||||||
|  |     @page limits Known Limitations | ||||||
|  |  | ||||||
|     - XML-Comments are only ignored, not read, not stored. |     - XML-Comments are only ignored, not read, not stored. | ||||||
|     - Mixed tags and text is not supported. Tags may either contain |     - Mixed tags and text is not supported. Tags may either contain | ||||||
| @@ -74,6 +153,23 @@ class MethodTrace { | |||||||
|       (e.g. <p><p><p></p></p></p>) |       (e.g. <p><p><p></p></p></p>) | ||||||
|     - Exceptions should be optional, best effort otherwise (option "strict") |     - Exceptions should be optional, best effort otherwise (option "strict") | ||||||
|  |  | ||||||
|  |     @see serializationLimits | ||||||
|  |  | ||||||
|  |     @page serializationLimits Limitations of Serialization | ||||||
|  |  | ||||||
|  |     - Only the following types are intended to be serialized:\n | ||||||
|  |       (It is possible to use other techniques, but that's not recommended) | ||||||
|  |        - basic C++ types (except pointer) | ||||||
|  |        - @c std::string | ||||||
|  |        - classes derieved from xml::Serialize | ||||||
|  |        - most standard containers, but in their xml-form, | ||||||
|  |          e.g. xml::List instead of @c std::list | ||||||
|  |          (xml::List inherits @c std::list) | ||||||
|  |     - @c std::bitset, @c std::priority_queue, @c std::queue and | ||||||
|  |       @c std::stack are not implemented | ||||||
|  |     - Optional values are not yet implemented | ||||||
|  |     - Polymorfic serialisation is not yet implemented | ||||||
|  |  | ||||||
|     @page rationale Rationale - Limitations of other libraries |     @page rationale Rationale - Limitations of other libraries | ||||||
|  |  | ||||||
|     The initial idea was to map C++ data structures to XML files |     The initial idea was to map C++ data structures to XML files | ||||||
| @@ -98,7 +194,7 @@ class MethodTrace { | |||||||
|     (http://gsoap.sf.net), boost serialization (http://boost.org) and |     (http://gsoap.sf.net), boost serialization (http://boost.org) and | ||||||
|     Qt XML (http://qtsoftware.com). |     Qt XML (http://qtsoftware.com). | ||||||
|      |      | ||||||
|     @section Qt XML, a typical DOM approach |     @section qtxml Qt XML, a typical DOM approach | ||||||
|  |  | ||||||
|     One is the XML part of the Qt library. These classes can read XML |     One is the XML part of the Qt library. These classes can read XML | ||||||
|     into a DOM tree, but then the user has to check for every detail. |     into a DOM tree, but then the user has to check for every detail. | ||||||
| @@ -118,25 +214,83 @@ class MethodTrace { | |||||||
|         ... |         ... | ||||||
|     @endcode |     @endcode | ||||||
|  |  | ||||||
|     @example address.cxx */ |     This is a typical example of a DOM parser. The main disadvantage | ||||||
|  |     here is that we cannot declare a schema. After parsing an XML | ||||||
|  |     file, we cannot know whether it is valid with respect to our | ||||||
|  |     definition or not. This means that every single access tested. | ||||||
|  |  | ||||||
|  |     xml::Factory lets you specify a schema template and guarantees | ||||||
|  |     that the parsed file passed a lot of tests to make sure it fits | ||||||
|  |     into the schema. If any test fails, the factory throws an | ||||||
|  |     exception. | ||||||
|  |  | ||||||
|  |     @section boostserialization Boost Serialization | ||||||
|  |  | ||||||
|  |     Boost serialization is quite flexible and easy to use, but there | ||||||
|  |     are several pitfalls, and worst, the generated XML cannot easily | ||||||
|  |     be edited by hand. One of the main problems: If you store lists, | ||||||
|  |     you cannot simply add an arbitrary number of list items, but you | ||||||
|  |     must first serialize the list size as a number. If you edit the | ||||||
|  |     file by hand, the number must exactly match the number of items, | ||||||
|  |     or parsing will fail. Error messages (the exceptions) don't help | ||||||
|  |     finding the problem within the parsed XML code. The XML format it | ||||||
|  |     generates is definitely not made to be edited by hand. | ||||||
|  |  | ||||||
|  |     In fact, in my project that resulted in this new class (CoMoL, see | ||||||
|  |     http://comol.sourceforge.net), we first used Boost serialization | ||||||
|  |     to read and write XML files. The configuration was then done on | ||||||
|  |     the GUI. But this was not comfortable enough, so the configuration | ||||||
|  |     was mostly edited by hand. It was a pain then to find any typos in | ||||||
|  |     the XML and the storage was too unflexible. So we needed a new | ||||||
|  |     apporach, and well here it is. CoMoL now uses the full flexibility | ||||||
|  |     of @ref freexml including optional tags and attributes. | ||||||
|  |  | ||||||
|  |     @section gsoap Using gSOAP for Serialization of C++ Structures | ||||||
|  |  | ||||||
|  |     When I was working at Siemens, we often used gSOAP | ||||||
|  |     (http://gsoap.sf.net) when we needed mor flexibility in XML | ||||||
|  |     declaration than what's possible with @ref boostserialization. But | ||||||
|  |     gSOAP has several problems: | ||||||
|  |  | ||||||
|  |       - It is a C framework, not native C++, with all the problems | ||||||
|  |         that result from this, i.e. memory management is absolutely | ||||||
|  |         awful. | ||||||
|  |       - It is a quite a complex problem to copy a gSOAP structure | ||||||
|  |         without memory access problems. | ||||||
|  |       - Moreover gSOAP is not real C++ code, but it requires a pre | ||||||
|  |         processor that generates C++ from a pseudo C++ structure. | ||||||
|  |       - It is not designed to Store C++ in XML, but to implement the | ||||||
|  |         gSOAP protocol. | ||||||
|  |       - And last but not least, the license is not free for all usage. | ||||||
|  |  | ||||||
|  |     @example address.cxx Example | ||||||
|  |  | ||||||
|  |     This is a simple example on how to declare a XML schema and how to | ||||||
|  |     use a xml::Factory to restore it from a file. */ | ||||||
|  |  | ||||||
|  | //! @addtogroup freexml | ||||||
|  | //@{ | ||||||
| /*! @defgroup xmlConst XML Constant Declarations | /*! @defgroup xmlConst XML Constant Declarations | ||||||
|  |  | ||||||
|     There are macros to help you with declaring constants. Chose a C++ |     There are macros to help you with declaring constants. Chose a C++ | ||||||
|     header fiel, where you want to declare constant names for your xml |     header file, where you want to declare constant names for your xml | ||||||
|     nodes. |     nodes. | ||||||
|  |  | ||||||
|     Then for every leaf xml::Node name you will use, call |     Then for xml::Node you will use, call XML_NODE(name) and for every | ||||||
|     XML_NODE(name) and for every xml::String call XML_STRING(name). |     xml::String call XML_STRING(othername). After the declaration, you | ||||||
|  |     can use the xml::Node as constant @c xml::node::name, the | ||||||
|  |     xml::String as constant @c xml::string::name and @c std::string | ||||||
|  |     constants for the given node names as @c xml::name::name and @c | ||||||
|  |     xml::name::othername. | ||||||
|  |  | ||||||
|     For every node with children call XML_PARENT(name, child1, child2 ...). |     @note If you want to use the xml::Node, xml::String constants in a | ||||||
|  |     non constant environment, i.e. to add children, attributes or | ||||||
|  |     limits, you must call xml::Node::clone to get a non constant copy. | ||||||
|  |  | ||||||
|     @note Node names must be unique. You can not even use the same |     @note Node names must be unique. You can not even use the same | ||||||
|     name for a XML_NODE and a XML_STRING declaration. |     name for a XML_NODE and a XML_STRING declaration. | ||||||
|  |  | ||||||
|     This code is from the examples: |     @see @ref node_macros.cxx | ||||||
|      |  | ||||||
|     @include node_macros.cxx |  | ||||||
|  |  | ||||||
|     @example node_macros.cxx |     @example node_macros.cxx | ||||||
|  |  | ||||||
| @@ -168,12 +322,17 @@ class MethodTrace { | |||||||
|     names are more often used than nodes. (@em Never use @c using in a |     names are more often used than nodes. (@em Never use @c using in a | ||||||
|     C++ header file, you would pollute the scope of all the |     C++ header file, you would pollute the scope of all the | ||||||
|     includers.) */ |     includers.) */ | ||||||
|  | //@} | ||||||
|  | //! @addtogroup xmlConst | ||||||
| //@{ | //@{ | ||||||
|  |  | ||||||
| //! Define a string for a node name | //! Define a string for a node name | ||||||
| /*! It is called inside XML_NODE and XML_STRING, so if you work with | /*! It is called inside XML_NODE and XML_STRING, so if you work with | ||||||
|     these two, you don't have to care about XML_NAME. But you can use |     these two, you don't have to care about XML_NAME. But you can use | ||||||
|     XML_NAME alone if you don't want the other two macros. |     XML_NAME alone if you don't want the other two macros. | ||||||
|  |  | ||||||
|  |     Declares a constant of type @c std::string with name @c xml::name::NAME. | ||||||
|  |      | ||||||
|     @see XML_NODE |     @see XML_NODE | ||||||
|     @see XML_STRING */ |     @see XML_STRING */ | ||||||
| #define XML_NAME(NAME) \ | #define XML_NAME(NAME) \ | ||||||
| @@ -233,8 +392,14 @@ class MethodTrace { | |||||||
|  |  | ||||||
| //@} | //@} | ||||||
|  |  | ||||||
| //! Represents classes for handling C++ access to XML files with strict schema. | /*! @defgroup freexml Arbitrary XML Schema Definition and Storage | ||||||
| /*! The schema ist not presented through xsd, but it can be declared in C++. |  | ||||||
|  |     Class xml::Node declares an XML DOM node. Storing XML structures | ||||||
|  |     has never been a problem, but to read them back again, | ||||||
|  |     xml::Factory is needed, which must be given an XML schema | ||||||
|  |     description. The XML schema is fully declared in C++, simply by | ||||||
|  |     shifting the allowed nodes and attributes into the factory and by | ||||||
|  |     setting limits. | ||||||
|  |  | ||||||
|     A xml::Factory represents a factory that owns a template and can |     A xml::Factory represents a factory that owns a template and can | ||||||
|     instanciate XML trees that are valid for the given template from |     instanciate XML trees that are valid for the given template from | ||||||
| @@ -286,8 +451,15 @@ class MethodTrace { | |||||||
|                <<x.what()<<std::endl; |                <<x.what()<<std::endl; | ||||||
|     } |     } | ||||||
|     @endcode */ |     @endcode */ | ||||||
|  |  | ||||||
|  | //! Everything is in namespace xml | ||||||
| namespace xml { | namespace xml { | ||||||
|  |  | ||||||
|  |   //! @addtogroup freexml | ||||||
|  |   //@{ | ||||||
|  |  | ||||||
|  |   //! @cond INTERNAL | ||||||
|  |  | ||||||
|   //============================================================================ |   //============================================================================ | ||||||
|   //! Type of an xml node. |   //! Type of an xml node. | ||||||
|   /*! Only start nodes and empty nodes may have attributes. */ |   /*! Only start nodes and empty nodes may have attributes. */ | ||||||
| @@ -300,6 +472,9 @@ namespace xml { | |||||||
|     //! a xml start indication <code><?xml?></code> |     //! a xml start indication <code><?xml?></code> | ||||||
|     //! or a document type declaration <code><!DOCTYPE ...></code> |     //! or a document type declaration <code><!DOCTYPE ...></code> | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   //! @endcond | ||||||
|  |  | ||||||
|   //! Declares an attribute to be mandatory. |   //! Declares an attribute to be mandatory. | ||||||
|   const bool mandatory(true); |   const bool mandatory(true); | ||||||
|   //! Declares an attribute to be optional. |   //! Declares an attribute to be optional. | ||||||
| @@ -311,6 +486,10 @@ namespace xml { | |||||||
|   class Node; |   class Node; | ||||||
|   class Factory; |   class Factory; | ||||||
|  |  | ||||||
|  |   //@} | ||||||
|  |   //! @defgroup exceptions Exception classes | ||||||
|  |   //@{ | ||||||
|  |    | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|   class exception: public std::exception { |   class exception: public std::exception { | ||||||
|     public: |     public: | ||||||
| @@ -330,6 +509,9 @@ namespace xml { | |||||||
|           exception("serialized node type is not registered\ntype: " |           exception("serialized node type is not registered\ntype: " | ||||||
|                     +type+"\nname: "+name, t) { |                     +type+"\nname: "+name, t) { | ||||||
|       } |       } | ||||||
|  |       type_not_registered(std::string type): | ||||||
|  |           exception("serialized node type is not registered\ntype: "+type) { | ||||||
|  |       } | ||||||
|   }; |   }; | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|   class empty_attribute_list: public exception { |   class empty_attribute_list: public exception { | ||||||
| @@ -421,6 +603,7 @@ namespace xml { | |||||||
|           stream_error("mismatching end tag", t, is, tag, c) { |           stream_error("mismatching end tag", t, is, tag, c) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class missing_end_tag: public stream_error { |   class missing_end_tag: public stream_error { | ||||||
|     public: |     public: | ||||||
|       missing_end_tag(const Node& t, std::istream& is, const Tag& tag, char c=0) |       missing_end_tag(const Node& t, std::istream& is, const Tag& tag, char c=0) | ||||||
| @@ -428,6 +611,7 @@ namespace xml { | |||||||
|           stream_error("missing end tag, end of file reached", t, is, tag, c) { |           stream_error("missing end tag, end of file reached", t, is, tag, c) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class wrong_start_tag: public stream_error { |   class wrong_start_tag: public stream_error { | ||||||
|     public: |     public: | ||||||
|       wrong_start_tag(const Node& t, std::istream& is, const Tag& tag, char c=0) |       wrong_start_tag(const Node& t, std::istream& is, const Tag& tag, char c=0) | ||||||
| @@ -435,6 +619,7 @@ namespace xml { | |||||||
|           stream_error("start tag does not match expected tag", t, is, tag, c) { |           stream_error("start tag does not match expected tag", t, is, tag, c) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class second_slash_in_tag: public stream_error { |   class second_slash_in_tag: public stream_error { | ||||||
|     public: |     public: | ||||||
|       second_slash_in_tag(const Node& t, std::istream& is, const Tag& tag, |       second_slash_in_tag(const Node& t, std::istream& is, const Tag& tag, | ||||||
| @@ -443,6 +628,7 @@ namespace xml { | |||||||
|           stream_error("a tag may have no more than one slash", t, is, tag, c) { |           stream_error("a tag may have no more than one slash", t, is, tag, c) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class character_after_slash: public stream_error { |   class character_after_slash: public stream_error { | ||||||
|     public: |     public: | ||||||
|       character_after_slash(const Node& t, std::istream& is, const Tag& tag, |       character_after_slash(const Node& t, std::istream& is, const Tag& tag, | ||||||
| @@ -452,6 +638,7 @@ namespace xml { | |||||||
|                        t, is, tag, c) { |                        t, is, tag, c) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class attributes_in_end_tag: public stream_error { |   class attributes_in_end_tag: public stream_error { | ||||||
|     public: |     public: | ||||||
|       attributes_in_end_tag(const Node& t, std::istream& is, const Tag& tag) |       attributes_in_end_tag(const Node& t, std::istream& is, const Tag& tag) | ||||||
| @@ -459,6 +646,7 @@ namespace xml { | |||||||
|           stream_error("attributes are not allowed in end tags",t, is, tag) { |           stream_error("attributes are not allowed in end tags",t, is, tag) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class attribute_value_not_quoted: public stream_error { |   class attribute_value_not_quoted: public stream_error { | ||||||
|     public: |     public: | ||||||
|       attribute_value_not_quoted(const Node& t, std::istream& is, |       attribute_value_not_quoted(const Node& t, std::istream& is, | ||||||
| @@ -468,6 +656,7 @@ namespace xml { | |||||||
|                        t, is, tag, c) { |                        t, is, tag, c) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class duplicate_attribute: public stream_error { |   class duplicate_attribute: public stream_error { | ||||||
|     public: |     public: | ||||||
|       duplicate_attribute(const Node& t, std::istream& is, const Tag& tag, |       duplicate_attribute(const Node& t, std::istream& is, const Tag& tag, | ||||||
| @@ -476,6 +665,7 @@ namespace xml { | |||||||
|                        t, is, tag, 0) { |                        t, is, tag, 0) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class illegal_attribute: public stream_error { |   class illegal_attribute: public stream_error { | ||||||
|     public: |     public: | ||||||
|       illegal_attribute(const Node& t, std::istream& is, const Tag& tag, |       illegal_attribute(const Node& t, std::istream& is, const Tag& tag, | ||||||
| @@ -484,6 +674,7 @@ namespace xml { | |||||||
|                        t, is, tag, 0) { |                        t, is, tag, 0) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class mandatory_attribute_missing: public stream_error { |   class mandatory_attribute_missing: public stream_error { | ||||||
|     public: |     public: | ||||||
|       mandatory_attribute_missing(const Node& t, std::istream& is, |       mandatory_attribute_missing(const Node& t, std::istream& is, | ||||||
| @@ -492,6 +683,7 @@ namespace xml { | |||||||
|                        t, is, tag, 0) { |                        t, is, tag, 0) { | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //---------------------------------------------------------------------------- | ||||||
|   class wrong_node_number: public stream_error { |   class wrong_node_number: public stream_error { | ||||||
|     public: |     public: | ||||||
|       wrong_node_number(const Node& t, std::istream& is, |       wrong_node_number(const Node& t, std::istream& is, | ||||||
| @@ -510,9 +702,13 @@ namespace xml { | |||||||
|         return ss.str(); |         return ss.str(); | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|  |   //! @} | ||||||
|  |  | ||||||
|   //============================================================================ |   //============================================================================ | ||||||
|  |  | ||||||
|  |   //! @addtogroup freexml | ||||||
|  |   //@{ | ||||||
|  |  | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|   //! Map for attribute values. |   //! Map for attribute values. | ||||||
|   /*! Attributes can be set using method xml::Node::attr(). Check for |   /*! Attributes can be set using method xml::Node::attr(). Check for | ||||||
| @@ -570,7 +766,7 @@ namespace xml { | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|   //! An xml Node. |   //! An xml Node that contains child nodes but no text. | ||||||
|   /*! XML Nodes may contain either text or other nodes, but not both |   /*! XML Nodes may contain either text or other nodes, but not both | ||||||
|       at the same time. This node can hold other nodes. For a Node for |       at the same time. This node can hold other nodes. For a Node for | ||||||
|       text contents, see xml::String. */ |       text contents, see xml::String. */ | ||||||
| @@ -639,6 +835,7 @@ namespace xml { | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|  |   //! A leaf node that contains text but no child nodes. | ||||||
|   class String: public Node { |   class String: public Node { | ||||||
|     public: |     public: | ||||||
|       String(std::string name, |       String(std::string name, | ||||||
| @@ -672,6 +869,7 @@ namespace xml { | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|  |   //! A leaf node that contains only numbers and no child nodes. | ||||||
|   class UnsignedInteger: public String { |   class UnsignedInteger: public String { | ||||||
|     public: |     public: | ||||||
|       UnsignedInteger(std::string name, unsigned long i=0, |       UnsignedInteger(std::string name, unsigned long i=0, | ||||||
| @@ -685,6 +883,52 @@ namespace xml { | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|  |   //! Factory to restore XML structures from a stream. | ||||||
|  |   /*! A xml::Factory must be given a template that declares the | ||||||
|  |       structure, before the factory can be used. This can be done | ||||||
|  |       either at instanciation or later by assignment. | ||||||
|  |  | ||||||
|  |       The template is a xml::Node that specifies the schema of the data | ||||||
|  |       that can be loaded from streams through a xml::Factory | ||||||
|  |       instance. | ||||||
|  |  | ||||||
|  |       The root element has automatically set the limits 1..1 | ||||||
|  |       (<code>xml::Node::limits(1, 1)</code>, see xml::Node::limits), | ||||||
|  |       which means that the root element must exist exactly once. If | ||||||
|  |       you pass another limit, your limit is overwritten and ignored. | ||||||
|  |  | ||||||
|  |       E.g. to load an address, that contains a tag <address> | ||||||
|  |       with at least a name and optional an address in it's body, you | ||||||
|  |       may write: | ||||||
|  |  | ||||||
|  |       @code | ||||||
|  |       xml::Factory addrTpl(xml::Node("address") | ||||||
|  |                            (<<xml::Node("name").limit(1, 1) | ||||||
|  |                             (<<xml::String("first").limit(1, 1) | ||||||
|  |                              <<xml::String("middle") // 0..n -> .limit(0, 0) | ||||||
|  |                              <<xml::String("last").limit(1, 1)) | ||||||
|  |                             <<(xml::Node("location").max(1) | ||||||
|  |                                <<xml::String("line").min(1)) | ||||||
|  |                             <<xml::String("country").max(1))); | ||||||
|  |       @endcode | ||||||
|  |  | ||||||
|  |       According to this example, a valid XML file could be: | ||||||
|  |        | ||||||
|  |       @verbatim | ||||||
|  |       <address> | ||||||
|  |         <name> | ||||||
|  |           <first>Marc</first> | ||||||
|  |           <middle>Roman</middle> | ||||||
|  |           <last>Wäckerlin</last> | ||||||
|  |         </name> | ||||||
|  |         <location> | ||||||
|  |           <line>SwissSign AG</line> | ||||||
|  |           <line>Pfingstweidstrasse 60b</line> | ||||||
|  |           <line>8005 Zürich</line> | ||||||
|  |         </location> | ||||||
|  |         <country>Schweiz</country> | ||||||
|  |       </address> | ||||||
|  |       @endverbatim */ | ||||||
|   class Factory { |   class Factory { | ||||||
|     public: |     public: | ||||||
|       Factory(const Node& t) throw(); |       Factory(const Node& t) throw(); | ||||||
| @@ -695,7 +939,8 @@ namespace xml { | |||||||
|       const Node*const operator->() const throw(factory_not_valid); |       const Node*const operator->() const throw(factory_not_valid); | ||||||
|       operator bool() const throw(); |       operator bool() const throw(); | ||||||
|       friend std::ostream& operator<<(std::ostream& os, |       friend std::ostream& operator<<(std::ostream& os, | ||||||
|                                       const Factory& factory) throw(); |                                       const Factory& factory) | ||||||
|  |           throw(factory_not_valid); | ||||||
|       static std::ostream& print(std::ostream& os, const Node& node, |       static std::ostream& print(std::ostream& os, const Node& node, | ||||||
|                                  unsigned int level=0) throw(); |                                  unsigned int level=0) throw(); | ||||||
|       std::auto_ptr<Node> read(std::istream& is) |       std::auto_ptr<Node> read(std::istream& is) | ||||||
| @@ -704,12 +949,14 @@ namespace xml { | |||||||
|                 missing_end_tag, attribute_value_not_quoted, access_error, |                 missing_end_tag, attribute_value_not_quoted, access_error, | ||||||
|                 duplicate_attribute, attributes_in_end_tag, |                 duplicate_attribute, attributes_in_end_tag, | ||||||
|                 illegal_attribute, mandatory_attribute_missing, |                 illegal_attribute, mandatory_attribute_missing, | ||||||
|                 wrong_node_number); |                 wrong_node_number, factory_not_valid); | ||||||
|       void reset() throw(); |       void reset() throw(); | ||||||
|     private: |     private: | ||||||
|       friend class stream_error; |       friend class stream_error; | ||||||
|       friend class Serialize; |       friend class Serialize; | ||||||
|       template<class T, class A> friend class List; |       template<class T> friend class Container; | ||||||
|  |       template<class T> friend class AssociativeContainer; | ||||||
|  |       template<class T> friend class AssociativeMap; | ||||||
|       Node& operator*() throw(factory_not_valid); |       Node& operator*() throw(factory_not_valid); | ||||||
|       Node*const operator->() throw(factory_not_valid); |       Node*const operator->() throw(factory_not_valid); | ||||||
|       bool ws(char c) throw(); |       bool ws(char c) throw(); | ||||||
| @@ -734,6 +981,7 @@ namespace xml { | |||||||
|       unsigned long _line; |       unsigned long _line; | ||||||
|       long _open; |       long _open; | ||||||
|   }; |   }; | ||||||
|  |   //@} | ||||||
|  |  | ||||||
|   /*! @defgroup serialization Class Serialization |   /*! @defgroup serialization Class Serialization | ||||||
|  |  | ||||||
| @@ -763,74 +1011,87 @@ namespace xml { | |||||||
|       @section serActual Actual Status |       @section serActual Actual Status | ||||||
|  |  | ||||||
|       The following member types are supported |       The following member types are supported | ||||||
|       - All built-in C++ types are supported |       - All built-in C++ types are supported, except enum | ||||||
|       - std::string is supported |       - @c std::string is supported | ||||||
|       - Contained classes are supported |       - Contained classes are supported | ||||||
|  |       - Inheritance | ||||||
|  |       - @ref serContainer | ||||||
|  |  | ||||||
|       The following will be supported soon (ideas): |       @todo The following will be supported soon (ideas): | ||||||
|       - lists, maps |  | ||||||
|       - inheritance |  | ||||||
|       - choices (one of) |       - choices (one of) | ||||||
|  |       - choices (polymorfism) | ||||||
|       - optional members (pointer) |       - optional members (pointer) | ||||||
|  |       - enum (class xml::Enum) | ||||||
|  |  | ||||||
|       Pointers cannot be stored. |       Pointers cannot be stored. | ||||||
|  |  | ||||||
|       There are many ways of implemenation. best practice is to |       @section serBestPract Best Practice and Inheritance | ||||||
|       inherit xml::Serialize and to overwrite |  | ||||||
|       xml::Serialize::initXmlMembers: |  | ||||||
|  |  | ||||||
|       @code |       There are many ways of implemenation (see example @ref | ||||||
|       class A: public xml::Serialize { |       serialization.cxx). best practice is to inherit xml::Serialize | ||||||
|         protected: |       and to overwrite xml::Serialize::initXmlMembers, as shown in the | ||||||
|           // all persitent members must be registered |       example @ref serialization.cxx. | ||||||
|           virtual void initXmlMembers() { |  | ||||||
|             className("A"); // giving a class name is very important |  | ||||||
|             persist(_anInteger, "anInteger"); |  | ||||||
|             persist(_aBool, "aBool"); |  | ||||||
|             persist(_aDouble, "aDouble"); |  | ||||||
|             persist(_aString, "aString"); |  | ||||||
|             persist(_anotherString, "anotherString"); |  | ||||||
|             persist(_aLong, "aLong"); |  | ||||||
|           } |  | ||||||
|         private: |  | ||||||
|           int _anInteger; |  | ||||||
|           bool _aBool; |  | ||||||
|           double _aDouble; |  | ||||||
|           std::string _aString; |  | ||||||
|           std::string _anotherString; |  | ||||||
|           unsigned long _aLong; |  | ||||||
|       }; |  | ||||||
|  |  | ||||||
|       class B: public xml::Serialize { |       @warning If you do not follow the best practice, you must know | ||||||
|         protected: |       what you are doing to prevent crashing: You must know that | ||||||
|           virtual void initXmlMembers() { |       xml::Serialize stores pointers to the variables given in | ||||||
|             className("B"); |       xml::Serialize::persist. So be careful and don't access | ||||||
|             persist(_a); // name must not be given, it's already known |       xml::Serialize after the referenced variables have been removed | ||||||
|             persist(_anInteger, "anInteger"); |       from memory. | ||||||
|           } |  | ||||||
|         private: |  | ||||||
|           A _a; // contains an A |  | ||||||
|           int _anInteger; |  | ||||||
|       }; |  | ||||||
|  |  | ||||||
|       int main(int, char**) { |       @subsection inheritance Inheritance | ||||||
|         A a; |  | ||||||
|         B b; |       If you follow the best practice and inherit from another class, | ||||||
|         // ... do something with a and b, then write it to stdout: |       you must first call method xml::Serialize::initXmlMembers of the | ||||||
|         a.saveXml(std::out)<<std::endl; |       parent class, then call xml::Serialize::className to set the new | ||||||
|         b.saveXml(std::out)<<std::endl; |       name of the child class. | ||||||
|         return 0; |  | ||||||
|       } |       @section examples Examples | ||||||
|       @endcode |  | ||||||
|  |       @see @ref serialization.cxx for the different approaches | ||||||
|  |       @see @ref contain_serialization.cxx for containment | ||||||
|  |       @see @ref inherit_serialization.cxx for inheritance | ||||||
|  |  | ||||||
|       @example serialization.cxx |       @example serialization.cxx | ||||||
|       @example contain_serialization.cxx */ |  | ||||||
|  |       In this example you see several apporoaches on how to connect | ||||||
|  |       variables to XML data structures to serialize them in | ||||||
|  |       XML. Please note, that <b>only class @c B</b> shows the | ||||||
|  |       recommended way of doing it. | ||||||
|  |  | ||||||
|  |       @warning Please note that xml::Serialize stores pointers to the | ||||||
|  |       variables that are serialized. If you access xml::Serialize | ||||||
|  |       outside of the life-cycle of any of the persistent variables, | ||||||
|  |       then your program may crash (in the best case) or even behave in | ||||||
|  |       an unexpected way. | ||||||
|  |  | ||||||
|  |       @example contain_serialization.cxx | ||||||
|  |  | ||||||
|  |       Handle containment in the recommended way. It's very simple: If | ||||||
|  |       all classes inherit from xml::Serialize, then containment | ||||||
|  |       behaves as expected. | ||||||
|  |  | ||||||
|  |       @example inherit_serialization.cxx | ||||||
|  |  | ||||||
|  |       This is an example for inheritance according the recommended way: | ||||||
|  |         - There's nothing special for the parent. | ||||||
|  |         - The child must do the following in xml::Serialize::initXmlMembers | ||||||
|  |           (the order is important!): | ||||||
|  |            -# call xml::Serialize::initXmlMembers of the parent | ||||||
|  |            -# call xml::Serialize::className to set the new class name | ||||||
|  |            -# call xml::Serialize::persist for all child members | ||||||
|  |         - The only difference is, that ... | ||||||
|  |             - ... the child does not inherit xml::Serialize, but a child of it | ||||||
|  |             - ... the child must first call xml::Serialize::initXmlMembers of | ||||||
|  |                   the parent in it's own xml::Serialize::initXmlMembers */ | ||||||
|  |   //! @addtogroup serialization | ||||||
|   //@{ |   //@{ | ||||||
|  |  | ||||||
|   class Serialize { |   class Serialize { | ||||||
|     public: |     public: | ||||||
|       typedef bool(*FromNodeFunc)(Any, const xml::Node&); |       typedef bool(*FromNodeFunc)(Any, const xml::Node&); | ||||||
|       typedef bool(*ToNodeFunc)(const Any, xml::Node&); |       typedef bool(*ToNodeFunc)(const Any, xml::Node&); | ||||||
|  |       typedef bool(*ClearFunc)(Any); | ||||||
|       //! You must call Serialize::className() if you use this constructor! |       //! You must call Serialize::className() if you use this constructor! | ||||||
|       Serialize() throw(); |       Serialize() throw(); | ||||||
|       Serialize(const std::string& className) throw(); |       Serialize(const std::string& className) throw(); | ||||||
| @@ -866,14 +1127,15 @@ namespace xml { | |||||||
|                          const std::string& name) throw(); |                          const std::string& name) throw(); | ||||||
|       Serialize& persist(std::string& member, |       Serialize& persist(std::string& member, | ||||||
|                          const std::string& name) throw(); |                          const std::string& name) throw(); | ||||||
|       std::ostream& saveXml(std::ostream& os, |       virtual std::ostream& saveXml(std::ostream& os, | ||||||
|                             const std::string& name = std::string()) |                                     const std::string& name = std::string()) | ||||||
|           const throw(); |           const throw(); | ||||||
|       std::istream& loadXml(std::istream& is, |       virtual std::istream& loadXml(std::istream& is, | ||||||
|                             const std::string& name = std::string()); |                                     const std::string& name = std::string()); | ||||||
|       std::string schema() const throw(); |       std::string schema() const throw(); | ||||||
|       static void registerFromNode(FromNodeFunc fromNodeFunc); |       static void registerFromNode(FromNodeFunc fromNodeFunc); | ||||||
|       static void registerToNode(ToNodeFunc toNodeFunc); |       static void registerToNode(ToNodeFunc toNodeFunc); | ||||||
|  |       static void registerClear(ClearFunc clearFunc); | ||||||
|     protected: |     protected: | ||||||
|       virtual void initXmlMembers(); |       virtual void initXmlMembers(); | ||||||
|       void checkInit(const Serialize* const ser=0) const { |       void checkInit(const Serialize* const ser=0) const { | ||||||
| @@ -883,8 +1145,12 @@ namespace xml { | |||||||
|           if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers(); |           if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers(); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     private: |       virtual void clear() throw(); | ||||||
|     public: //! @todo |       /*! @todo Why does @c protected: not work here?!? Children can't | ||||||
|  |           access the members if they are protected! */ | ||||||
|  |     public: | ||||||
|  |       //! @cond INTERNAL | ||||||
|  |       void clear(Any member) throw(); | ||||||
|       void reset() throw(); |       void reset() throw(); | ||||||
|       void copy(const Serialize& o) throw(); |       void copy(const Serialize& o) throw(); | ||||||
|       template<typename TYPE> |       template<typename TYPE> | ||||||
| @@ -896,85 +1162,210 @@ namespace xml { | |||||||
|         _xmlFactory = schema; |         _xmlFactory = schema; | ||||||
|         return *this; |         return *this; | ||||||
|       } |       } | ||||||
|       virtual void fromNode(Any member, const xml::Node& node); |       void fromNode(Any member, const xml::Node& node); | ||||||
|       virtual void toNode(const Any member, xml::Node& node) const; |       void toNode(const Any member, xml::Node& node) const; | ||||||
|       /* |  | ||||||
|       template<typename TYPE, class ALLOC> |  | ||||||
|           void fromNode(std::list<TYPE, ALLOC>* member, xml::Node& node) { |  | ||||||
|         member->clear(); |  | ||||||
|         for (xml::Node::size_type i(0); i<node.children(); ++i) |  | ||||||
|           ... |  | ||||||
|           }*/ |  | ||||||
|       std::map<std::string, Any> _xmlNames; |       std::map<std::string, Any> _xmlNames; | ||||||
|       xml::Factory _xmlFactory; |       xml::Factory _xmlFactory; | ||||||
|       static std::set<FromNodeFunc> _fromNode; |       static std::set<FromNodeFunc> _fromNode; | ||||||
|       static std::set<ToNodeFunc> _toNode; |       static std::set<ToNodeFunc> _toNode; | ||||||
|  |       static std::set<ClearFunc> _clear; | ||||||
|  |       //! @endcond | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   const int MAX_NUM(14); |   template <class TYPE> class Optional: public Serialize { | ||||||
|  |  | ||||||
|   template<int NUM> struct ToType {typedef Serialize      Type;}; |  | ||||||
|   template<> struct ToType<1>     {typedef Serialize      Type;}; |  | ||||||
|   template<> struct ToType<2>     {typedef std::string    Type;}; |  | ||||||
|   template<> struct ToType<3>     {typedef bool           Type;}; |  | ||||||
|   template<> struct ToType<4>     {typedef unsigned char  Type;}; |  | ||||||
|   template<> struct ToType<5>     {typedef signed   char  Type;}; |  | ||||||
|   template<> struct ToType<6>     {typedef          char  Type;}; |  | ||||||
|   template<> struct ToType<7>     {typedef unsigned short Type;}; |  | ||||||
|   template<> struct ToType<8>     {typedef signed   short Type;}; |  | ||||||
|   template<> struct ToType<9>     {typedef unsigned int   Type;}; |  | ||||||
|   template<> struct ToType<10>    {typedef signed   int   Type;}; |  | ||||||
|   template<> struct ToType<11>    {typedef unsigned long  Type;}; |  | ||||||
|   template<> struct ToType<12>    {typedef signed   long  Type;}; |  | ||||||
|   template<> struct ToType<13>    {typedef float          Type;}; |  | ||||||
|   template<> struct ToType<14>    {typedef double         Type;}; |  | ||||||
|    |  | ||||||
|   template<typename T> struct ToNum       {static const int NUM = 1;}; |  | ||||||
|   template<> struct ToNum<Serialize     > {static const int NUM = 1;}; |  | ||||||
|   template<> struct ToNum<std::string   > {static const int NUM = 2;}; |  | ||||||
|   template<> struct ToNum<bool          > {static const int NUM = 3;}; |  | ||||||
|   template<> struct ToNum<unsigned char > {static const int NUM = 4;}; |  | ||||||
|   template<> struct ToNum<signed   char > {static const int NUM = 5;}; |  | ||||||
|   template<> struct ToNum<         char > {static const int NUM = 6;}; |  | ||||||
|   template<> struct ToNum<unsigned short> {static const int NUM = 7;}; |  | ||||||
|   template<> struct ToNum<signed   short> {static const int NUM = 8;}; |  | ||||||
|   template<> struct ToNum<unsigned int  > {static const int NUM = 9;}; |  | ||||||
|   template<> struct ToNum<signed   int  > {static const int NUM = 10;}; |  | ||||||
|   template<> struct ToNum<unsigned long > {static const int NUM = 11;}; |  | ||||||
|   template<> struct ToNum<signed   long > {static const int NUM = 12;}; |  | ||||||
|   template<> struct ToNum<float         > {static const int NUM = 13;}; |  | ||||||
|   template<> struct ToNum<double        > {static const int NUM = 14;}; |  | ||||||
|  |  | ||||||
|   template<typename T> bool isSerialize() { |  | ||||||
|     return ToNum<T>::NUM == 1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   template <typename T, bool GOOD=(ToNum<T>::NUM==1)> struct Mapper { |  | ||||||
|       static Serialize* toSerialize(T& obj) { |  | ||||||
|         return 0; |  | ||||||
|       } |  | ||||||
|   }; |  | ||||||
|   template <typename T> struct Mapper<T, true> { |  | ||||||
|       static Serialize* toSerialize(T& obj) { |  | ||||||
|         return dynamic_cast<Serialize*>(&obj); |  | ||||||
|       } |  | ||||||
|   }; |  | ||||||
|    |  | ||||||
|   template<class TYPE, class ALLOC=std::allocator<TYPE> > class List: |  | ||||||
|       public std::list<TYPE, ALLOC>, public Serialize { |  | ||||||
|     public: |     public: | ||||||
|       List() {} |       Optional() throw() {} | ||||||
|       List(const List& o): std::list<TYPE, ALLOC>(o), Serialize(o) {} |       Optional(const Optional& o) throw(): _member(new TYPE(*o._member)) {} | ||||||
|       List(const std::string& className) throw(): Serialize(className) {} |       Optional(const TYPE& mem) throw(): _member(new TYPE(mem)) {} | ||||||
|       virtual ~List() {} |       virtual ~Optional() throw() {} | ||||||
|  |       Optional& operator=(const Optional& o) throw() { | ||||||
|  |         _member = new TYPE(*o._member); | ||||||
|  |         return *this; | ||||||
|  |       } | ||||||
|  |       Optional& operator=(const TYPE& mem) throw() { | ||||||
|  |         _member = new TYPE(mem); | ||||||
|  |         return *this; | ||||||
|  |       } | ||||||
|  |       operator bool() const throw() { | ||||||
|  |         return _member.get(); | ||||||
|  |       } | ||||||
|  |       const TYPE& operator*() const throw() { | ||||||
|  |         return *_member; | ||||||
|  |       } | ||||||
|  |       TYPE& operator*() throw() { | ||||||
|  |         return *_member; | ||||||
|  |       } | ||||||
|  |       const TYPE*const operator->() const throw() { | ||||||
|  |         return _member.get(); | ||||||
|  |       } | ||||||
|  |       TYPE*const operator->() throw() { | ||||||
|  |         return _member.get(); | ||||||
|  |       } | ||||||
|  |       Optional& reset() throw() { | ||||||
|  |         _member.reset(); | ||||||
|  |         return *this; | ||||||
|  |       } | ||||||
|  |     protected: | ||||||
|  |       virtual void clear() throw() { | ||||||
|  |         _member.reset(); | ||||||
|  |       } | ||||||
|  |       virtual std::ostream& saveXml(std::ostream& os, | ||||||
|  |                                     const std::string& name = std::string()) | ||||||
|  |           const throw() { | ||||||
|  |         if (!_member.get()) return os; | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Node node(*_xmlFactory); | ||||||
|  |         if (name.size()) node.name(name); | ||||||
|  |         toNode(*_member, node); | ||||||
|  |         os<<node; | ||||||
|  |         return os; | ||||||
|  |       } | ||||||
|  |     private: | ||||||
|  |       std::auto_ptr<TYPE> _member; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   //! @addtogroup serialization | ||||||
|  |   //@{ | ||||||
|  |   /*! @defgroup serContainer Serialization of Container | ||||||
|  |  | ||||||
|  |       libxml-cpp can serialize container, such as Lists, Vectors or | ||||||
|  |       Maps. Classes that serialize cannot contain standard C++ | ||||||
|  |       container directly, but they must contain container defined | ||||||
|  |       here. For every standard container except @c std::bitset there | ||||||
|  |       is a XML representation available. | ||||||
|  |  | ||||||
|  |       The following containers are defined: | ||||||
|  |       - xml::DeQue (inherits @c std::deque and xml::Serialize) | ||||||
|  |       - xml::List (inherits @c std::list and xml::Serialize) | ||||||
|  |       - xml::Map (inherits @c std::map and xml::Serialize) | ||||||
|  |       - xml::MultiMap (inherits @c std::multimap and xml::Serialize) | ||||||
|  |       - xml::MultiSet (inherits @c std::multiset and xml::Serialize) | ||||||
|  |       - xml::Set (inherits @c std::set and xml::Serialize) | ||||||
|  |       - xml::Vector (inherits @c std::vector and xml::Serialize) | ||||||
|  |  | ||||||
|  |       E.g. use @c xml::List instead of @c std::list. | ||||||
|  |  | ||||||
|  |       I don't see any necessity to implement @c std::priority_queue, | ||||||
|  |       @c std::queue and @c std::stack, they are only restricted | ||||||
|  |       interfaces to another container and don't allow random access | ||||||
|  |       (which is needed to store them). | ||||||
|  |  | ||||||
|  |       @example list_serialization.cxx */ | ||||||
|  |   //@} | ||||||
|  |  | ||||||
|  |   //! @cond INTERNAL | ||||||
|  |   template<class CONTAINER_TYPE> class Container: | ||||||
|  |       public CONTAINER_TYPE, | ||||||
|  |       public Serialize { | ||||||
|  |     public: | ||||||
|  |       Container() {} | ||||||
|  |       Container(const Container& o): CONTAINER_TYPE(o), Serialize(o) {} | ||||||
|  |       Container(const std::string& className) throw(): Serialize(className) {} | ||||||
|  |       virtual ~Container() {} | ||||||
|  |       virtual std::istream& loadXml(std::istream& is, | ||||||
|  |                                     const std::string& name = std::string()) { | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Factory factory(_xmlFactory); | ||||||
|  |         if (name.size()) factory->name(name); | ||||||
|  |         std::auto_ptr<xml::Node> node(factory.read(is)); | ||||||
|  |         CONTAINER_TYPE::clear(); | ||||||
|  |         for (xml::Node::size_type i(0); i<node->children(); ++i) { | ||||||
|  |           typename CONTAINER_TYPE::value_type tmp; | ||||||
|  |           Serialize::fromNode(&tmp, (*node)[i]); // reads into tmp | ||||||
|  |           push_back(tmp); | ||||||
|  |         } | ||||||
|  |         return is; | ||||||
|  |       } | ||||||
|  |       virtual std::ostream& saveXml(std::ostream& os, | ||||||
|  |                                     const std::string& name = std::string()) | ||||||
|  |           const throw() { | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Node node(*_xmlFactory); | ||||||
|  |         if (name.size()) node.name(name); | ||||||
|  |         std::auto_ptr<xml::Node> tpl(node[0].clone()); | ||||||
|  |         node.clear(); | ||||||
|  |         for (typename Container::const_iterator it = this->begin(); | ||||||
|  |              it!=this->end(); ++it) { | ||||||
|  |           typename CONTAINER_TYPE::value_type tmp; | ||||||
|  |           tmp = *it; | ||||||
|  |           std::auto_ptr<xml::Node> item(tpl->clone()); | ||||||
|  |           Serialize::toNode(&tmp, *item); | ||||||
|  |           node<<*item; | ||||||
|  |         } | ||||||
|  |         os<<node; | ||||||
|  |         return os; | ||||||
|  |       } | ||||||
|     protected: |     protected: | ||||||
|       virtual void initXmlMembers() { |       virtual void initXmlMembers() { | ||||||
|         std::string itemName("item"); |         std::string itemName("item"); | ||||||
|         TYPE tmp; |         typename CONTAINER_TYPE::value_type tmp; | ||||||
|         LOG("initXmlMembers List for: "<<typeid(TYPE).name()); |         if (isSerialize<typename CONTAINER_TYPE::value_type>()) { | ||||||
|         if (isSerialize<TYPE>()) { |           Serialize* ser(Mapper<typename CONTAINER_TYPE::value_type> | ||||||
|           LOG("Liste von Serialize"); |                          ::toSerialize(tmp)); | ||||||
|           Serialize* ser(Mapper<TYPE>::toSerialize(tmp)); |           checkInit(ser); | ||||||
|  |           itemName = ser->_xmlFactory->name(); | ||||||
|  |         } | ||||||
|  |         _xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc) | ||||||
|  |         persist(tmp, itemName); // add as child of dummyroot | ||||||
|  |         (*_xmlFactory)[0].limits(0, 0); // any number of children possible | ||||||
|  |       } | ||||||
|  |       virtual void clear() throw() { | ||||||
|  |         CONTAINER_TYPE::clear(); | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |    | ||||||
|  |   template<class CONTAINER_TYPE> class AssociativeContainer: | ||||||
|  |       public CONTAINER_TYPE, | ||||||
|  |       public Serialize { | ||||||
|  |     public: | ||||||
|  |       AssociativeContainer() {} | ||||||
|  |       AssociativeContainer(const AssociativeContainer& o): | ||||||
|  |           CONTAINER_TYPE(o), Serialize(o) { | ||||||
|  |       } | ||||||
|  |       AssociativeContainer(const std::string& className) throw(): | ||||||
|  |           Serialize(className) { | ||||||
|  |       } | ||||||
|  |       virtual ~AssociativeContainer() {} | ||||||
|  |       virtual std::istream& loadXml(std::istream& is, | ||||||
|  |                                     const std::string& name = std::string()) { | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Factory factory(_xmlFactory); | ||||||
|  |         if (name.size()) factory->name(name); | ||||||
|  |         std::auto_ptr<xml::Node> node(factory.read(is)); | ||||||
|  |         CONTAINER_TYPE::clear(); | ||||||
|  |         for (xml::Node::size_type i(0); i<node->children(); ++i) { | ||||||
|  |           typename CONTAINER_TYPE::value_type tmp; | ||||||
|  |           Serialize::fromNode(&tmp, (*node)[i]); // reads into tmp | ||||||
|  |           insert(tmp); | ||||||
|  |         } | ||||||
|  |         return is; | ||||||
|  |       } | ||||||
|  |       virtual std::ostream& saveXml(std::ostream& os, | ||||||
|  |                                     const std::string& name = std::string()) | ||||||
|  |           const throw() { | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Node node(*_xmlFactory); | ||||||
|  |         if (name.size()) node.name(name); | ||||||
|  |         std::auto_ptr<xml::Node> tpl(node[0].clone()); | ||||||
|  |         node.clear(); | ||||||
|  |         for (typename CONTAINER_TYPE::const_iterator it = this->begin(); | ||||||
|  |              it!=this->end(); ++it) { | ||||||
|  |           typename CONTAINER_TYPE::value_type tmp; | ||||||
|  |           tmp = *it; | ||||||
|  |           std::auto_ptr<xml::Node> item(tpl->clone()); | ||||||
|  |           Serialize::toNode(&tmp, *item); | ||||||
|  |           node<<*item; | ||||||
|  |         } | ||||||
|  |         os<<node; | ||||||
|  |         return os; | ||||||
|  |       } | ||||||
|  |     protected: | ||||||
|  |       virtual void initXmlMembers() { | ||||||
|  |         std::string itemName("item"); | ||||||
|  |         typename CONTAINER_TYPE::value_type tmp; | ||||||
|  |         if (isSerialize<typename CONTAINER_TYPE::value_type>()) { | ||||||
|  |           Serialize* ser(Mapper<typename CONTAINER_TYPE::value_type> | ||||||
|  |                          ::toSerialize(tmp)); | ||||||
|           assert(ser); |           assert(ser); | ||||||
|           assert(ser!=this); |           assert(ser!=this); | ||||||
|           assert((void*)ser==(void*)&tmp); |           assert((void*)ser==(void*)&tmp); | ||||||
| @@ -982,34 +1373,231 @@ namespace xml { | |||||||
|           itemName = ser->_xmlFactory->name(); |           itemName = ser->_xmlFactory->name(); | ||||||
|         } |         } | ||||||
|         _xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc) |         _xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc) | ||||||
|         persist(tmp, itemName); // add _reference as child of dummyroot |         persist(tmp, itemName); // add as child of dummyroot | ||||||
|         (*_xmlFactory)[0].limits(0, 0); // any number of children possible |         (*_xmlFactory)[0].limits(0, 0); // any number of children possible | ||||||
|       } |       } | ||||||
|       virtual void fromNode(Any member, const xml::Node& node) { |       virtual void clear() throw() { | ||||||
|         this->clear(); |         CONTAINER_TYPE::clear(); | ||||||
|         for (xml::Node::size_type i(0); i<node.parent().children(); ++i) { |  | ||||||
|           TYPE tmp; |  | ||||||
|           Serialize::fromNode(&tmp, node.parent()[i]); // reads into tmp |  | ||||||
|           push_back(tmp); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       virtual void toNode(const Any member, xml::Node& node) const { |  | ||||||
|         std::auto_ptr<xml::Node> tpl(node.clone()); |  | ||||||
|         xml::Node& parent(node.parent()); |  | ||||||
|         parent.clear(); // "node" is now invalid |  | ||||||
|         for (typename List::const_iterator it = this->begin(); |  | ||||||
|              it!=this->end(); ++it) { |  | ||||||
|           TYPE tmp; |  | ||||||
|           tmp = *it; |  | ||||||
|           std::auto_ptr<xml::Node> item(tpl->clone()); |  | ||||||
|           Serialize::toNode(&tmp, *item); |  | ||||||
|           parent<<*item; |  | ||||||
|         } |  | ||||||
|       } |       } | ||||||
|   }; |   }; | ||||||
|    |    | ||||||
|   //@} |   template<class CONTAINER_TYPE> class AssociativeMap: | ||||||
|  |       public CONTAINER_TYPE, | ||||||
|  |       public Serialize { | ||||||
|  |     public: | ||||||
|  |       AssociativeMap() {} | ||||||
|  |       AssociativeMap(const AssociativeMap& o): | ||||||
|  |           CONTAINER_TYPE(o), Serialize(o) { | ||||||
|  |       } | ||||||
|  |       AssociativeMap(const std::string& className) throw(): | ||||||
|  |           Serialize(className) { | ||||||
|  |       } | ||||||
|  |       virtual ~AssociativeMap() {} | ||||||
|  |       virtual std::istream& loadXml(std::istream& is, | ||||||
|  |                                     const std::string& name = std::string()) { | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Factory factory(_xmlFactory); | ||||||
|  |         if (name.size()) factory->name(name); | ||||||
|  |         std::auto_ptr<xml::Node> node(factory.read(is)); | ||||||
|  |         CONTAINER_TYPE::clear(); | ||||||
|  |         LOG("READING: "<<*node); | ||||||
|  |         for (xml::Node::size_type i(0); i<node->children(); ++i) { | ||||||
|  |           typename CONTAINER_TYPE::key_type key; | ||||||
|  |           typename CONTAINER_TYPE::mapped_type data; | ||||||
|  |           LOG("READING Key: "<<(*node)[i]<<"Value:"<<(*node)[1+i]); | ||||||
|  |           Serialize::fromNode(&key, (*node)[i]); // reads into tmp | ||||||
|  |           Serialize::fromNode(&data, (*node)[++i]); // key&value | ||||||
|  |           insert(typename CONTAINER_TYPE::value_type(key, data)); | ||||||
|  |           LOG("READ"); | ||||||
|  |         } | ||||||
|  |         LOG("DONE"); | ||||||
|  |         return is; | ||||||
|  |       } | ||||||
|  |       virtual std::ostream& saveXml(std::ostream& os, | ||||||
|  |                                     const std::string& name = std::string()) | ||||||
|  |           const throw() { | ||||||
|  |         checkInit(); | ||||||
|  |         xml::Node node(*_xmlFactory); | ||||||
|  |         if (name.size()) node.name(name); | ||||||
|  |         std::auto_ptr<xml::Node> tpl1(node[0].clone()); | ||||||
|  |         std::auto_ptr<xml::Node> tpl2(node[1].clone()); | ||||||
|  |         node.clear(); // "node" is now invalid | ||||||
|  |         for (typename AssociativeMap::const_iterator it = this->begin(); | ||||||
|  |              it!=this->end(); ++it) { | ||||||
|  |           typename CONTAINER_TYPE::key_type key; | ||||||
|  |           typename CONTAINER_TYPE::mapped_type data; | ||||||
|  |           key = it->first; | ||||||
|  |           data = it->second; | ||||||
|  |           std::auto_ptr<xml::Node> item1(tpl1->clone()); | ||||||
|  |           Serialize::toNode(&key, *item1); | ||||||
|  |           std::auto_ptr<xml::Node> item2(tpl2->clone()); | ||||||
|  |           Serialize::toNode(&data, *item2); | ||||||
|  |           node<<*item1<<*item2; | ||||||
|  |         } | ||||||
|  |         os<<node; | ||||||
|  |         return os; | ||||||
|  |       } | ||||||
|  |     protected: | ||||||
|  |       virtual void initXmlMembers() { | ||||||
|  |         std::string keyName("key"); | ||||||
|  |         std::string valueName("value"); | ||||||
|  |         typename CONTAINER_TYPE::key_type key; | ||||||
|  |         typename CONTAINER_TYPE::mapped_type data; | ||||||
|  |         if (isSerialize<typename CONTAINER_TYPE::key_type>()) { | ||||||
|  |           const Serialize* ser(Mapper<typename CONTAINER_TYPE::key_type> | ||||||
|  |                                ::toSerialize(key)); | ||||||
|  |           checkInit(ser); | ||||||
|  |           keyName = ser->_xmlFactory->name(); | ||||||
|  |         } | ||||||
|  |         if (isSerialize<typename CONTAINER_TYPE::mapped_type>()) { | ||||||
|  |           Serialize* ser(Mapper<typename CONTAINER_TYPE::mapped_type> | ||||||
|  |                          ::toSerialize(data)); | ||||||
|  |           checkInit(ser); | ||||||
|  |           valueName = ser->_xmlFactory->name(); | ||||||
|  |         } | ||||||
|  |         _xmlFactory = xml::Node("dummyroot"); // dummy root, (uninitialized exc) | ||||||
|  |         persist(key, keyName); // add as child of dummyroot | ||||||
|  |         persist(data, valueName); // add as child of dummyroot | ||||||
|  |         (*_xmlFactory)[0].limits(0, 0); // any number of children possible | ||||||
|  |         (*_xmlFactory)[1].limits(0, 0); // any number of children possible | ||||||
|  |       } | ||||||
|  |       virtual void clear() throw() { | ||||||
|  |         CONTAINER_TYPE::clear(); | ||||||
|  |       } | ||||||
|  |   }; | ||||||
|  |   //! @endcond | ||||||
|    |    | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //! @cond INTERNAL | ||||||
|  | //! @addtogroup  serContainer | ||||||
|  | //@{ | ||||||
|  | # ifdef __XML_CXX_DECLARE_CONTAINER_CLASS__ | ||||||
|  | #   error Macro __XML_CXX_DECLARE_CONTAINER_CLASS__ has been used elsewhere | ||||||
|  | # endif | ||||||
|  | # define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER)  \ | ||||||
|  |   namespace xml {                                                       \ | ||||||
|  |     template<class TYPE, class ALLOC=std::allocator<TYPE> >             \ | ||||||
|  |       class CONTAINER:                                                  \ | ||||||
|  |                     public Container<STD_CONTAINER<TYPE, ALLOC> > {     \ | ||||||
|  |         public:                                                         \ | ||||||
|  |           CONTAINER() {}                                                \ | ||||||
|  |           CONTAINER(const CONTAINER& o):                                \ | ||||||
|  |               Container<STD_CONTAINER<TYPE, ALLOC> >(o) {               \ | ||||||
|  |           }                                                             \ | ||||||
|  |           CONTAINER(const std::string& className) throw():              \ | ||||||
|  |               Container<STD_CONTAINER<TYPE, ALLOC> >(className) {       \ | ||||||
|  |           }                                                             \ | ||||||
|  |           virtual ~CONTAINER() {}                                       \ | ||||||
|  |       };                                                                \ | ||||||
|  |   } | ||||||
|  | # include <list> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(List, std::list); | ||||||
|  | # include <vector> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(Vector, std::vector); | ||||||
|  | # include <deque> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(Deque, std::deque); | ||||||
|  | # undef __XML_CXX_DECLARE_CONTAINER_CLASS__ | ||||||
|  | # define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER)  \ | ||||||
|  |   namespace xml {                                                       \ | ||||||
|  |     template<class TYPE, class CONT=std::deque<TYPE> >                  \ | ||||||
|  |       class CONTAINER:                                                  \ | ||||||
|  |           public AssociativeContainer                                   \ | ||||||
|  |                  <STD_CONTAINER<TYPE, CONT> > {                         \ | ||||||
|  |         public:                                                         \ | ||||||
|  |           CONTAINER() {}                                                \ | ||||||
|  |           CONTAINER(const CONTAINER& o):                                \ | ||||||
|  |               AssociativeContainer                                      \ | ||||||
|  |               <STD_CONTAINER<TYPE, CONT> >(o) {                         \ | ||||||
|  |           }                                                             \ | ||||||
|  |           CONTAINER(const std::string& className) throw():              \ | ||||||
|  |               AssociativeContainer                                      \ | ||||||
|  |               <STD_CONTAINER<TYPE, CONT> >                              \ | ||||||
|  |               (className) {                                             \ | ||||||
|  |           }                                                             \ | ||||||
|  |           virtual ~CONTAINER() {}                                       \ | ||||||
|  |     };                                                                  \ | ||||||
|  |   } | ||||||
|  | # include <stack> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(Stack, std::stack); | ||||||
|  | # include <queue> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(Queue, std::queue); | ||||||
|  | # undef __XML_CXX_DECLARE_CONTAINER_CLASS__ | ||||||
|  | # define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER)  \ | ||||||
|  |   namespace xml {                                                       \ | ||||||
|  |     template                                                            \ | ||||||
|  |         <class TYPE, class CONT=std::vector<TYPE>,                      \ | ||||||
|  |         class COMPARE=std::less<TYPE>,                                  \ | ||||||
|  |         class ALLOC=std::allocator<TYPE> >                              \ | ||||||
|  |             class CONTAINER:                                            \ | ||||||
|  |               public AssociativeContainer                               \ | ||||||
|  |                   <STD_CONTAINER<TYPE, COMPARE, ALLOC> > {              \ | ||||||
|  |               public:                                                   \ | ||||||
|  |                 CONTAINER() {}                                          \ | ||||||
|  |                 CONTAINER(const CONTAINER& o):                          \ | ||||||
|  |                     AssociativeContainer                                \ | ||||||
|  |                     <STD_CONTAINER<TYPE, COMPARE, ALLOC> >(o) {         \ | ||||||
|  |                 }                                                       \ | ||||||
|  |                 CONTAINER(const std::string& className) throw():        \ | ||||||
|  |                     AssociativeContainer                                \ | ||||||
|  |                     <STD_CONTAINER<TYPE, COMPARE, ALLOC> >              \ | ||||||
|  |                     (className) {                                       \ | ||||||
|  |                 }                                                       \ | ||||||
|  |                 virtual ~CONTAINER() {}                                 \ | ||||||
|  |             };                                                          \ | ||||||
|  |   } | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(PriorityQueue, std::priority_queue); | ||||||
|  | # undef __XML_CXX_DECLARE_CONTAINER_CLASS__ | ||||||
|  | # define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER)  \ | ||||||
|  |   namespace xml {                                                       \ | ||||||
|  |     template<class TYPE, class COMPARE=std::less<TYPE>,                 \ | ||||||
|  |         class ALLOC=std::allocator<TYPE> >                              \ | ||||||
|  |             class CONTAINER:                                            \ | ||||||
|  |               public AssociativeContainer                               \ | ||||||
|  |                   <STD_CONTAINER<TYPE, COMPARE, ALLOC> > {              \ | ||||||
|  |               public:                                                   \ | ||||||
|  |                 CONTAINER() {}                                          \ | ||||||
|  |                 CONTAINER(const CONTAINER& o):                          \ | ||||||
|  |                     AssociativeContainer                                \ | ||||||
|  |                     <STD_CONTAINER<TYPE, COMPARE, ALLOC> >(o) {         \ | ||||||
|  |                 }                                                       \ | ||||||
|  |                 CONTAINER(const std::string& className) throw():        \ | ||||||
|  |                     AssociativeContainer                                \ | ||||||
|  |                     <STD_CONTAINER<TYPE, COMPARE, ALLOC> >              \ | ||||||
|  |                     (className) {                                       \ | ||||||
|  |                 }                                                       \ | ||||||
|  |                 virtual ~CONTAINER() {}                                 \ | ||||||
|  |             };                                                          \ | ||||||
|  |   } | ||||||
|  | # include <set> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(Set, std::set); | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(MultiSet, std::multiset); | ||||||
|  | # undef __XML_CXX_DECLARE_CONTAINER_CLASS__ | ||||||
|  | # define __XML_CXX_DECLARE_CONTAINER_CLASS__(CONTAINER, STD_CONTAINER)  \ | ||||||
|  |   namespace xml {                                                       \ | ||||||
|  |     template<class KEY, class VALUE, class COMPARE=std::less<KEY>,      \ | ||||||
|  |         class ALLOC=std::allocator<std::pair<const KEY, VALUE> > >      \ | ||||||
|  |         class CONTAINER: public AssociativeMap                          \ | ||||||
|  |             <STD_CONTAINER<KEY, VALUE, COMPARE, ALLOC> > {              \ | ||||||
|  |           public:                                                       \ | ||||||
|  |             CONTAINER() {}                                              \ | ||||||
|  |             CONTAINER(const CONTAINER& o):                              \ | ||||||
|  |                 AssociativeMap                                          \ | ||||||
|  |                 <STD_CONTAINER<KEY, VALUE, COMPARE, ALLOC> >(o) {       \ | ||||||
|  |             }                                                           \ | ||||||
|  |             CONTAINER(const std::string& className) throw():            \ | ||||||
|  |                 AssociativeMap                                          \ | ||||||
|  |                 <STD_CONTAINER<KEY, VALUE, COMPARE, ALLOC> >            \ | ||||||
|  |                 (className) {                                           \ | ||||||
|  |             }                                                           \ | ||||||
|  |             virtual ~CONTAINER() {}                                     \ | ||||||
|  |         };                                                              \ | ||||||
|  |   } | ||||||
|  | # include <map> | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(Map, std::map); | ||||||
|  | __XML_CXX_DECLARE_CONTAINER_CLASS__(MultiMap, std::multimap); | ||||||
|  | # undef __XML_CXX_DECLARE_CONTAINER_CLASS__ | ||||||
|  | //@} | ||||||
|  | //! @endcond | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										205
									
								
								src/xml.cxx
									
									
									
									
									
								
							
							
						
						
									
										205
									
								
								src/xml.cxx
									
									
									
									
									
								
							| @@ -718,76 +718,48 @@ namespace xml { | |||||||
|  |  | ||||||
|   //---------------------------------------------------------------------------- |   //---------------------------------------------------------------------------- | ||||||
|   //! To instanciate a factory, a template must be given. |   //! To instanciate a factory, a template must be given. | ||||||
|   /*! The template is a node that specifies the schema of the data |  | ||||||
|       that can be loaded from streams through a xml::Factory |  | ||||||
|       instance. |  | ||||||
|  |  | ||||||
|       The root element has automatically set the limits 1..1 |  | ||||||
|       (<code>xml::Node::limits(1, 1)</code>, see xml::Node::limits), |  | ||||||
|       which means that the root element must exist exactly once. If |  | ||||||
|       you pass another limit, your limit is overwritten. |  | ||||||
|  |  | ||||||
|       E.g. to load an address, that contains a tag <address> |  | ||||||
|       with at least a name and optional an address in it's body, you |  | ||||||
|       may write: |  | ||||||
|  |  | ||||||
|       @code |  | ||||||
|       xml::Factory addrTpl(xml::Node("address") |  | ||||||
|                            (<<xml::Node("name").limit(1, 1) |  | ||||||
|                             (<<xml::String("first").limit(1, 1) |  | ||||||
|                              <<xml::String("middle") // 0..n -> .limit(0, 0) |  | ||||||
|                              <<xml::String("last").limit(1, 1)) |  | ||||||
|                             <<(xml::Node("location").max(1) |  | ||||||
|                                <<xml::String("line").min(1)) |  | ||||||
|                             <<xml::String("country").max(1))); |  | ||||||
|       @endcode |  | ||||||
|  |  | ||||||
|       According to this example, a valid XML file could be: |  | ||||||
|        |  | ||||||
|       @verbatim |  | ||||||
|       <address> |  | ||||||
|         <name> |  | ||||||
|           <first>Marc</first> |  | ||||||
|           <middle>Roman</middle> |  | ||||||
|           <last>Wäckerlin</last> |  | ||||||
|         </name> |  | ||||||
|         <location> |  | ||||||
|           <line>SwissSign AG</line> |  | ||||||
|           <line>Pfingstweidstrasse 60b</line> |  | ||||||
|           <line>8005 Zürich</line> |  | ||||||
|         </location> |  | ||||||
|         <country>Schweiz</country> |  | ||||||
|       </address> |  | ||||||
|       @endverbatim */ |  | ||||||
|   Factory::Factory(const Node& t) throw(): |   Factory::Factory(const Node& t) throw(): | ||||||
|       _template(xml::Node("<xml::start>")<<t), _line(0) { |       _template(xml::Node("<xml::start>")<<t), _line(0) { | ||||||
|     _template[0].min(1); |     _template[0].min(1); | ||||||
|     _template[0].max(1); |     _template[0].max(1); | ||||||
|   } |   } | ||||||
|  |   //! Instanciates an invalid factory. A template must be assigned later. | ||||||
|   Factory::Factory() throw(): |   Factory::Factory() throw(): | ||||||
|       _template(xml::Node("<xml::start>")), _line(0) { |       _template(xml::Node("<xml::start>")), _line(0) { | ||||||
|   } |   } | ||||||
|  |   //! Assign a template. | ||||||
|  |   /*! If you don't pass a template at instanciation, you must call | ||||||
|  |       this method later, or you will get xml::factory_not_valid | ||||||
|  |       exceptions when you try to use the factory. */ | ||||||
|   Factory& Factory::operator=(const Node& t) throw() { |   Factory& Factory::operator=(const Node& t) throw() { | ||||||
|     _template = xml::Node("<xml::start>")<<t; |     _template = xml::Node("<xml::start>")<<t; | ||||||
|     _template[0].min(1); |     _template[0].min(1); | ||||||
|     _template[0].max(1); |     _template[0].max(1); | ||||||
|   } |   } | ||||||
|  |   //! Get the template. | ||||||
|   const Node& Factory::operator*() const throw(factory_not_valid) try { |   const Node& Factory::operator*() const throw(factory_not_valid) try { | ||||||
|     return _template[0]; |     return _template[0]; | ||||||
|   } catch (...) { |   } catch (...) { | ||||||
|     throw factory_not_valid(); |     throw factory_not_valid(); | ||||||
|   } |   } | ||||||
|  |   //! Access the (root node of the) template. | ||||||
|   const Node*const Factory::operator->() const throw(factory_not_valid) try { |   const Node*const Factory::operator->() const throw(factory_not_valid) try { | ||||||
|     return &_template[0]; |     return &_template[0]; | ||||||
|   } catch (...) { |   } catch (...) { | ||||||
|     throw factory_not_valid(); |     throw factory_not_valid(); | ||||||
|   } |   } | ||||||
|  |   //! Check whether the factory has been given a valid template. | ||||||
|   Factory::operator bool() const throw() { |   Factory::operator bool() const throw() { | ||||||
|     return _template.children()>0; |     return _template.children()>0; | ||||||
|   } |   } | ||||||
|   std::ostream& operator<<(std::ostream& os, const Factory& factory) throw() { |   //! Print the factory template's schema in human readable format. | ||||||
|  |   /*! Calls xml::Factory::print */ | ||||||
|  |   std::ostream& operator<<(std::ostream& os, const Factory& factory) | ||||||
|  |       throw(factory_not_valid) { | ||||||
|     return factory.print(os, *factory); |     return factory.print(os, *factory); | ||||||
|   } |   } | ||||||
|  |   //! Print a node's schema description in human readable format. | ||||||
|  |   /*! @todo May be changed to a XML Schema output later. */ | ||||||
|   std::ostream& Factory::print(std::ostream& os, const Node& node, |   std::ostream& Factory::print(std::ostream& os, const Node& node, | ||||||
|                                unsigned int level) throw() { |                                unsigned int level) throw() { | ||||||
|     if (node.children()) { |     if (node.children()) { | ||||||
| @@ -842,6 +814,7 @@ namespace xml { | |||||||
|     } |     } | ||||||
|     return os; |     return os; | ||||||
|   } |   } | ||||||
|  |   //! Restore a xml::Node tree from a stream, according to the given schema. | ||||||
|   std::auto_ptr<Node> Factory::read(std::istream& is) |   std::auto_ptr<Node> Factory::read(std::istream& is) | ||||||
|       throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch, |       throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch, | ||||||
|             second_slash_in_tag, |             second_slash_in_tag, | ||||||
| @@ -849,16 +822,20 @@ namespace xml { | |||||||
|             access_error, duplicate_attribute, |             access_error, duplicate_attribute, | ||||||
|             attributes_in_end_tag, |             attributes_in_end_tag, | ||||||
|             illegal_attribute, mandatory_attribute_missing, |             illegal_attribute, mandatory_attribute_missing, | ||||||
|             wrong_node_number) try { |             wrong_node_number, factory_not_valid) { | ||||||
|     _line=1; |     if (_template.children()==0) throw factory_not_valid(); | ||||||
|     _open=0; |     try { | ||||||
|     std::auto_ptr<Node> node(read(is, _template)); |       _line=1; | ||||||
|     if (node->children()==0) |       _open=0; | ||||||
|       throw tag_expected(_template[0], "nothing found, possibly empty stream"); |       std::auto_ptr<Node> node(read(is, _template)); | ||||||
|     return (*node)[0].clone(); |       if (node->children()==0) | ||||||
|   } catch (exception& e) { |         throw tag_expected(_template[0], | ||||||
|     e.line(_line); |                            "nothing found, possibly empty stream"); | ||||||
|     throw; |       return (*node)[0].clone(); | ||||||
|  |     } catch (exception& e) { | ||||||
|  |       e.line(_line); | ||||||
|  |       throw; | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   void Factory::reset() throw() { |   void Factory::reset() throw() { | ||||||
|     _line = 0; |     _line = 0; | ||||||
| @@ -1124,7 +1101,10 @@ namespace xml { | |||||||
|     for (std::map<std::string, Any>::const_iterator |     for (std::map<std::string, Any>::const_iterator | ||||||
|            it(_xmlNames.begin()); |            it(_xmlNames.begin()); | ||||||
|          it!=_xmlNames.end(); ++it) |          it!=_xmlNames.end(); ++it) | ||||||
|       fromNode(it->second, (*node)[it->first]); |       if ((*node)(it->first)) | ||||||
|  |         fromNode(it->second, (*node)[it->first]); | ||||||
|  |       else | ||||||
|  |         clear(it->second); | ||||||
|     return is; |     return is; | ||||||
|   } |   } | ||||||
|   std::string Serialize::schema() const throw() { |   std::string Serialize::schema() const throw() { | ||||||
| @@ -1137,10 +1117,18 @@ namespace xml { | |||||||
|   void Serialize::registerFromNode(Serialize::FromNodeFunc fromNodeFunc) { |   void Serialize::registerFromNode(Serialize::FromNodeFunc fromNodeFunc) { | ||||||
|     _fromNode.insert(fromNodeFunc); |     _fromNode.insert(fromNodeFunc); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void Serialize::registerToNode(Serialize::ToNodeFunc toNodeFunc) { |   void Serialize::registerToNode(Serialize::ToNodeFunc toNodeFunc) { | ||||||
|     _toNode.insert(toNodeFunc); |     _toNode.insert(toNodeFunc); | ||||||
|   } |   } | ||||||
|  |   void Serialize::registerClear(Serialize::ClearFunc clearFunc) { | ||||||
|  |     _clear.insert(clearFunc); | ||||||
|  |   } | ||||||
|  |   void Serialize::clear() throw() { | ||||||
|  |     for (std::map<std::string, Any>::const_iterator | ||||||
|  |            it(_xmlNames.begin()); | ||||||
|  |          it!=_xmlNames.end(); ++it) | ||||||
|  |       clear(it->second); | ||||||
|  |   } | ||||||
|   void Serialize::initXmlMembers() {} |   void Serialize::initXmlMembers() {} | ||||||
|   void Serialize::reset() throw() { |   void Serialize::reset() throw() { | ||||||
|     _xmlFactory.reset(); |     _xmlFactory.reset(); | ||||||
| @@ -1154,127 +1142,116 @@ namespace xml { | |||||||
|     for (std::set<FromNodeFunc>::const_iterator it(_fromNode.begin()); |     for (std::set<FromNodeFunc>::const_iterator it(_fromNode.begin()); | ||||||
|          it!=_fromNode.end(); ++it) |          it!=_fromNode.end(); ++it) | ||||||
|       if ((**it)(member, node)) return; // found match |       if ((**it)(member, node)) return; // found match | ||||||
|     /* |     throw type_not_registered(member.type().name(), node.name(), node); | ||||||
|     if (!RealType<member>::isSerialize()) |  | ||||||
|         */ |  | ||||||
|       throw type_not_registered(member.type().name(), node.name(), node); |  | ||||||
|       /* |  | ||||||
|     Serialize* ser(RealType<TYPE>::serialize(member, 0)); |  | ||||||
|     // from assignFromNode<Serialize> |  | ||||||
|     //! @todo improve this (inefficient) |  | ||||||
|     std::stringstream ss; // simple but inefficient: rewrite and reread |  | ||||||
|     ss<<node; |  | ||||||
|     ser->loadXml(ss, node.name()); |  | ||||||
|         */ |  | ||||||
|   } |   } | ||||||
|   void Serialize::toNode(const Any member, xml::Node& node) const { |   void Serialize::toNode(const Any member, xml::Node& node) const { | ||||||
|     for (std::set<ToNodeFunc>::const_iterator it(_toNode.begin()); |     for (std::set<ToNodeFunc>::const_iterator it(_toNode.begin()); | ||||||
|          it!=_toNode.end(); ++it) |          it!=_toNode.end(); ++it) | ||||||
|       if ((**it)(member, node)) return; // found match |       if ((**it)(member, node)) return; // found match | ||||||
|     /* |     throw type_not_registered(member.type().name(), node.name(), node); | ||||||
|     if (!RealType<TYPE>::isSerialize()) |   } | ||||||
|         */ |   void Serialize::clear(Any member) throw() { | ||||||
|       throw type_not_registered(member.type().name(), node.name(), node); |     for (std::set<ClearFunc>::const_iterator it(_clear.begin()); | ||||||
|       /* |          it!=_clear.end(); ++it) | ||||||
|     // from assignToNode<Serialize> |       if ((**it)(member)) return; // found match | ||||||
|     std::stringstream ss; |     throw type_not_registered(member.type().name()); | ||||||
|     ((Serialize*)member)->saveXml(ss, node.name()); |  | ||||||
|     xml::Factory factory(node); |  | ||||||
|     node = *factory.read(ss); |  | ||||||
|         */ |  | ||||||
|   } |   } | ||||||
|   std::set<Serialize::FromNodeFunc> Serialize::_fromNode; |   std::set<Serialize::FromNodeFunc> Serialize::_fromNode; | ||||||
|   std::set<Serialize::ToNodeFunc> Serialize::_toNode; |   std::set<Serialize::ToNodeFunc> Serialize::_toNode; | ||||||
|  |   std::set<Serialize::ClearFunc> Serialize::_clear; | ||||||
|    |    | ||||||
|   //=============================================================== Assign Types |   //=============================================================== Assign Types | ||||||
|   template<typename TYPE> bool assignFromNode(Any member, |   template<typename TYPE> bool assignFromNode(Any member, | ||||||
|                                               const xml::Node& node) { |                                               const xml::Node& node) { | ||||||
|     if (!any_cast<TYPE*>(&member)) return false; |     if (!any_cast<TYPE>(&member)) return false; | ||||||
|     *any_cast<TYPE*>(member) = |     *any_cast<TYPE>(member) = | ||||||
|       (TYPE)dynamic_cast<const xml::String&>(node); |       (TYPE)dynamic_cast<const xml::String&>(node); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   template<typename TYPE> bool assignToNode(const Any member, |   template<typename TYPE> bool assignToNode(const Any member, | ||||||
|                                             xml::Node& node) { |                                             xml::Node& node) { | ||||||
|     if (!any_cast<TYPE*>(&member)) return false; |     if (!any_cast<TYPE>(&member)) return false; | ||||||
|     std::stringstream ss; |     std::stringstream ss; | ||||||
|     ss<<*any_cast<TYPE*>(member); |     ss<<*any_cast<TYPE>(member); | ||||||
|     node.text(ss.str()); |     node.text(ss.str()); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   template<> bool assignFromNode<bool>(Any member, |   template<> bool assignFromNode<bool>(Any member, | ||||||
|                                        const xml::Node& node) { |                                        const xml::Node& node) { | ||||||
|     if (member.type()!=typeid(bool*)) return false; |     if (member.type()!=typeid(bool)) return false; | ||||||
|     std::string s(*dynamic_cast<const xml::String&>(node)); |     std::string s(*dynamic_cast<const xml::String&>(node)); | ||||||
|     std::string::size_type |     std::string::size_type | ||||||
|       start(s.find_first_not_of(" \t\n\r")), |       start(s.find_first_not_of(" \t\n\r")), | ||||||
|       end(s.find_last_not_of(" \t\n\r")); |       end(s.find_last_not_of(" \t\n\r")); | ||||||
|     if (start==std::string::npos) { |     if (start==std::string::npos) { | ||||||
|       *any_cast<bool*>(member) = false; |       *any_cast<bool>(member) = false; | ||||||
|     } else { |     } else { | ||||||
|       s = s.substr(start, end-start+1); |       s = s.substr(start, end-start+1); | ||||||
|       *any_cast<bool*>(member) =  |       *any_cast<bool>(member) =  | ||||||
|         s!="0" && s!="false" && s!="no" && s!="off"; |         s!="0" && s!="false" && s!="no" && s!="off"; | ||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   template<> bool assignToNode<bool>(const Any member, |   template<> bool assignToNode<bool>(const Any member, | ||||||
|                                      xml::Node& node) { |                                      xml::Node& node) { | ||||||
|     if (member.type()!=typeid(bool*)) return false; |     if (member.type()!=typeid(bool)) return false; | ||||||
|     node.text(*any_cast<bool*>(member)?"true":"false"); |     node.text(*any_cast<bool>(member)?"true":"false"); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   template<> bool assignFromNode<Serialize>(Any member, |   template<> bool assignFromNode<Serialize>(Any member, | ||||||
|                                             const xml::Node& node) { |                                             const xml::Node& node) { | ||||||
|     if (!any_cast<Serialize*>(&member)) return false; |     if (!any_cast<Serialize>(&member)) return false; | ||||||
|     //! @todo improve this (inefficient) |     //! @todo improve this (inefficient) | ||||||
|     std::stringstream ss; // simple but inefficient: rewrite and reread |     std::stringstream ss; // simple but inefficient: rewrite and reread | ||||||
|     ss<<node; |     ss<<node; | ||||||
|     any_cast<Serialize*>(member)->loadXml(ss, node.name()); |     any_cast<Serialize>(member)->loadXml(ss, node.name()); | ||||||
|     /* |     /* | ||||||
|     Serialize* ser(any_cast<Serialize*>(member)); |     Serialize* ser(any_cast<Serialize>(member)); | ||||||
|     for (xml::Node::size_type i(0); i<node.children(); ++i) |     for (xml::Node::size_type i(0); i<node.children(); ++i) | ||||||
|         ser->fromNode(ser->_xmlNames[*node[i]], node[i]);*/ |         ser->fromNode(ser->_xmlNames[*node[i]], node[i]);*/ | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   template<> bool assignToNode<Serialize>(const Any member, |   template<> bool assignToNode<Serialize>(const Any member, | ||||||
|                                           xml::Node& node) { |                                           xml::Node& node) { | ||||||
|     if (!any_cast<Serialize*>(&member)) return false; |     if (!any_cast<Serialize>(&member)) return false; | ||||||
|     std::stringstream ss; |     std::stringstream ss; | ||||||
|     any_cast<Serialize*>(member)->saveXml(ss, node.name()); |     any_cast<Serialize>(member)->saveXml(ss, node.name()); | ||||||
|     xml::Factory factory(node); |     xml::Factory factory(node); | ||||||
|     node = *factory.read(ss); |     node = *factory.read(ss); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|   // Register for all simple Types ============================================= |   //================================================================ Clear Types | ||||||
|   template<int NUM> struct SimpleTypes {}; |   template<typename TYPE> bool clearMember(Any member) { | ||||||
|   template<> struct SimpleTypes<1>  {typedef Serialize      Type;}; |     if (!any_cast<TYPE>(&member)) return false; | ||||||
|   template<> struct SimpleTypes<2>  {typedef std::string    Type;}; |     *any_cast<TYPE>(member) = 0; | ||||||
|   template<> struct SimpleTypes<3>  {typedef bool           Type;}; |     return true; | ||||||
|   template<> struct SimpleTypes<4>  {typedef unsigned char  Type;}; |   } | ||||||
|   template<> struct SimpleTypes<5>  {typedef signed   char  Type;}; |   template<> bool clearMember<bool>(Any member) { | ||||||
|   template<> struct SimpleTypes<6>  {typedef          char  Type;}; |     if (member.type()!=typeid(bool)) return false; | ||||||
|   template<> struct SimpleTypes<7>  {typedef unsigned short Type;}; |     *any_cast<bool>(member) = false; | ||||||
|   template<> struct SimpleTypes<8>  {typedef signed   short Type;}; |     return true; | ||||||
|   template<> struct SimpleTypes<9>  {typedef          short Type;}; |   } | ||||||
|   template<> struct SimpleTypes<10> {typedef unsigned int   Type;}; |   template<> bool clearMember<std::string>(Any member) { | ||||||
|   template<> struct SimpleTypes<11> {typedef signed   int   Type;}; |     if (member.type()!=typeid(bool)) return false; | ||||||
|   template<> struct SimpleTypes<12> {typedef          int   Type;}; |     any_cast<std::string>(member)->clear(); | ||||||
|   template<> struct SimpleTypes<13> {typedef unsigned long  Type;}; |     return true; | ||||||
|   template<> struct SimpleTypes<14> {typedef signed   long  Type;}; |   } | ||||||
|   template<> struct SimpleTypes<15> {typedef          long  Type;}; |   template<> bool clearMember<Serialize>(Any member) { | ||||||
|   template<> struct SimpleTypes<16> {typedef float          Type;}; |     if (!any_cast<Serialize>(&member)) return false; | ||||||
|   template<> struct SimpleTypes<17> {typedef double         Type;}; |     any_cast<std::string>(member)->clear(); | ||||||
|   const int START_NUM(17); |     return true; | ||||||
|  |   } | ||||||
|   // Init To and From Node --------------------------------------------------- |   // Init To and From Node --------------------------------------------------- | ||||||
|   namespace { |   namespace { | ||||||
|     template<int NUM=START_NUM> struct RegisterTemplateForStdTypes { |     template<int NUM=MAX_NUM> struct RegisterTemplateForStdTypes { | ||||||
|         RegisterTemplateForStdTypes<NUM-1> next; // recurse to next until 0 |         RegisterTemplateForStdTypes<NUM-1> next; // recurse to next until 0 | ||||||
|         RegisterTemplateForStdTypes() { |         RegisterTemplateForStdTypes() { | ||||||
|           Serialize::registerToNode |           Serialize::registerToNode | ||||||
|             (&assignToNode<typename SimpleTypes<NUM>::Type>); |             (&assignToNode<typename ToType<NUM>::Type>); | ||||||
|           Serialize::registerFromNode |           Serialize::registerFromNode | ||||||
|             (&assignFromNode<typename SimpleTypes<NUM>::Type>); |             (&assignFromNode<typename ToType<NUM>::Type>); | ||||||
|  |           Serialize::registerClear | ||||||
|  |             (&clearMember<typename ToType<NUM>::Type>); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|     template<> struct RegisterTemplateForStdTypes<0> {}; // stop recursion |     template<> struct RegisterTemplateForStdTypes<0> {}; // stop recursion | ||||||
|   | |||||||
							
								
								
									
										173
									
								
								test/container_serialization_test.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								test/container_serialization_test.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | |||||||
|  | /*! @file | ||||||
|  |  | ||||||
|  |     @id $Id: serialization_test.cxx 31 2009-04-28 07:36:07Z  $ | ||||||
|  | */ | ||||||
|  | //       1         2         3         4         5         6         7         8 | ||||||
|  | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
|  | #include <xml-cxx/xml.hxx> | ||||||
|  | #include <cppunit/TestFixture.h> | ||||||
|  | #include <cppunit/ui/text/TestRunner.h> | ||||||
|  | #include <cppunit/extensions/HelperMacros.h> | ||||||
|  | #include <cppunit/extensions/TestFactoryRegistry.h> | ||||||
|  |  | ||||||
|  | class A: public xml::Serialize { | ||||||
|  |   public: | ||||||
|  |     int _int; | ||||||
|  |     unsigned _unsigned; | ||||||
|  |     bool operator<(const A& o) const { | ||||||
|  |       return _int<o._int || _int==o._int && _unsigned<o._unsigned; | ||||||
|  |     } | ||||||
|  |   protected: | ||||||
|  |     void initXmlMembers() { | ||||||
|  |       className("A"); | ||||||
|  |       persist(_int, "int"); | ||||||
|  |       persist(_unsigned, "unsigned"); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class B: public xml::Serialize { | ||||||
|  |   public: | ||||||
|  |     long _long; | ||||||
|  |     short _short; | ||||||
|  |   protected: | ||||||
|  |     void initXmlMembers() { | ||||||
|  |       className("B"); | ||||||
|  |       persist(_long, "long"); | ||||||
|  |       persist(_short, "short"); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class B2: public B { | ||||||
|  |   public: | ||||||
|  |     double _double; | ||||||
|  |   protected: | ||||||
|  |     void initXmlMembers() { | ||||||
|  |       B::initXmlMembers(); | ||||||
|  |       className("B2"); | ||||||
|  |       persist(_double, "double"); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class C: public xml::Serialize { | ||||||
|  |   public: | ||||||
|  |     xml::Map<A, B2> _map; | ||||||
|  |   protected: | ||||||
|  |     void initXmlMembers() { | ||||||
|  |       className("C"); | ||||||
|  |       persist(_map, "map"); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class C2: public C { | ||||||
|  |   public: | ||||||
|  |     xml::Set<std::string> _set; | ||||||
|  |   protected: | ||||||
|  |     void initXmlMembers() { | ||||||
|  |       C::initXmlMembers(); | ||||||
|  |       className("C2"); | ||||||
|  |       persist(_set, "set"); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class D: public xml::Serialize { | ||||||
|  |   public: | ||||||
|  |     xml::Vector<C2> _vector; | ||||||
|  |   protected: | ||||||
|  |     void initXmlMembers() { | ||||||
|  |       className("D"); | ||||||
|  |       persist(_vector, "vector"); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ContainerSerializationTest: public CppUnit::TestFixture { | ||||||
|  |   public: | ||||||
|  |     void checkContainers() { | ||||||
|  |       // instanciate all container to find template compilation errors | ||||||
|  |       xml::Deque<int> c1; | ||||||
|  |       xml::List<int> c2; | ||||||
|  |       xml::Map<int, int> c3; | ||||||
|  |       xml::MultiMap<int, int> c4; | ||||||
|  |       xml::MultiSet<int> c5; | ||||||
|  |       //xml::PriorityQueue<int> c6; | ||||||
|  |       //xml::Queue<int> c7; | ||||||
|  |       xml::Set<int> c8; | ||||||
|  |       //xml::Stack<int> c9; | ||||||
|  |       xml::Vector<int> c10; | ||||||
|  |       // no test | ||||||
|  |       std::string file("<D>\n" | ||||||
|  |                        "\t<vector>\n" | ||||||
|  |                        "\t\t<C2>\n" | ||||||
|  |                        "\t\t\t<map>\n" | ||||||
|  |                        "\t\t\t\t<A>\n" | ||||||
|  |                        "\t\t\t\t\t<int>-13</int>\n" | ||||||
|  |                        "\t\t\t\t\t<unsigned>13</unsigned>\n" | ||||||
|  |                        "\t\t\t\t</A>\n" | ||||||
|  |                        "\t\t\t\t<B2>\n" | ||||||
|  |                        "\t\t\t\t\t<long>1234567890</long>\n" | ||||||
|  |                        "\t\t\t\t\t<short>123</short>\n" | ||||||
|  |                        "\t\t\t\t\t<double>1.234</double>\n" | ||||||
|  |                        "\t\t\t\t</B2>\n" | ||||||
|  |                        "\t\t\t\t<A>\n" | ||||||
|  |                        "\t\t\t\t\t<int>-1</int>\n" | ||||||
|  |                        "\t\t\t\t\t<unsigned>2</unsigned>\n" | ||||||
|  |                        "\t\t\t\t</A>\n" | ||||||
|  |                        "\t\t\t\t<B2>\n" | ||||||
|  |                        "\t\t\t\t\t<long>451236789</long>\n" | ||||||
|  |                        "\t\t\t\t\t<short>43</short>\n" | ||||||
|  |                        "\t\t\t\t\t<double>15.34</double>\n" | ||||||
|  |                        "\t\t\t\t</B2>\n" | ||||||
|  |                        "\t\t\t</map>\n" | ||||||
|  |                        "\t\t\t<set>\n" | ||||||
|  |                        "\t\t\t\t<item>Hello</item>\n" | ||||||
|  |                        "\t\t\t\t<item>World</item>\n" | ||||||
|  |                        "\t\t\t</set>\n" | ||||||
|  |                        "\t\t</C2>\n" | ||||||
|  |                        "\t\t<C2>\n" | ||||||
|  |                        "\t\t\t<map/>\n" | ||||||
|  |                        "\t\t\t<set/>\n" | ||||||
|  |                        "\t\t</C2>\n" | ||||||
|  |                        "\t</vector>\n" | ||||||
|  |                        "</D>"); | ||||||
|  |       std::stringstream ss(file); | ||||||
|  |       D d; | ||||||
|  |       CPPUNIT_ASSERT_EQUAL(std::string("<D>\n" | ||||||
|  |                                        "\t<vector>\n" | ||||||
|  |                                        "\t\t<C2>\n" | ||||||
|  |                                        "\t\t\t<map>\n" | ||||||
|  |                                        "\t\t\t\t<A>\n" | ||||||
|  |                                        "\t\t\t\t\t<int/>\n" | ||||||
|  |                                        "\t\t\t\t\t<unsigned/>\n" | ||||||
|  |                                        "\t\t\t\t</A>\n" | ||||||
|  |                                        "\t\t\t\t<B2>\n" | ||||||
|  |                                        "\t\t\t\t\t<long/>\n" | ||||||
|  |                                        "\t\t\t\t\t<short/>\n" | ||||||
|  |                                        "\t\t\t\t\t<double/>\n" | ||||||
|  |                                        "\t\t\t\t</B2>\n" | ||||||
|  |                                        "\t\t\t</map>\n" | ||||||
|  |                                        "\t\t\t<set>\n" | ||||||
|  |                                        "\t\t\t\t<item/>\n" | ||||||
|  |                                        "\t\t\t</set>\n" | ||||||
|  |                                        "\t\t</C2>\n" | ||||||
|  |                                        "\t</vector>\n" | ||||||
|  |                                        "</D>"), | ||||||
|  |                            d.schema()); | ||||||
|  |       CPPUNIT_ASSERT_NO_THROW(d.loadXml(ss)); | ||||||
|  |       std::stringstream ss2; | ||||||
|  |       CPPUNIT_ASSERT_NO_THROW(d.saveXml(ss2)); | ||||||
|  |       CPPUNIT_ASSERT_EQUAL(file, ss2.str()); | ||||||
|  |     } | ||||||
|  |     CPPUNIT_TEST_SUITE(ContainerSerializationTest); | ||||||
|  |     CPPUNIT_TEST(checkContainers); | ||||||
|  |     CPPUNIT_TEST_SUITE_END(); | ||||||
|  | }; | ||||||
|  | CPPUNIT_TEST_SUITE_REGISTRATION(ContainerSerializationTest); | ||||||
|  |  | ||||||
|  | int main() try { | ||||||
|  |   CppUnit::TextUi::TestRunner runner; | ||||||
|  |   runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); | ||||||
|  |   return runner.run() ? 0 : 1; | ||||||
|  |  } catch (std::exception& e) { | ||||||
|  |   std::cerr<<"***Exception: "<<e.what()<<std::endl; | ||||||
|  |   return 1; | ||||||
|  |  } | ||||||
| @@ -7,11 +7,12 @@ AM_CXXFLAGS += -I ${top_srcdir}/src | |||||||
| AM_LDFLAGS = -L${top_builddir}/src | AM_LDFLAGS = -L${top_builddir}/src | ||||||
| LDADD = -lcppunit -lxml-cxx | LDADD = -lcppunit -lxml-cxx | ||||||
|  |  | ||||||
| check_PROGRAMS = xml_test serialization_test | check_PROGRAMS = xml_test serialization_test container_serialization_test | ||||||
| TESTS=${check_PROGRAMS} | TESTS=${check_PROGRAMS} | ||||||
|  |  | ||||||
| xml_test_SOURCES = xml_test.cxx | xml_test_SOURCES = xml_test.cxx | ||||||
| serialization_test_SOURCES = serialization_test.cxx | serialization_test_SOURCES = serialization_test.cxx | ||||||
|  | container_serialization_test_SOURCES = container_serialization_test.cxx | ||||||
|  |  | ||||||
| CLEANFILES =  | CLEANFILES =  | ||||||
| MAINTAINERCLEANFILES = makefile.in | MAINTAINERCLEANFILES = makefile.in | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user