Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: giken9_HTMLServer_Temp_Sample
expatpp.h@1:e96b2af301dd, 2011-05-26 (annotated)
- Committer:
 - andrewbonney
 - Date:
 - Thu May 26 10:03:14 2011 +0000
 - Revision:
 - 1:e96b2af301dd
 - Parent:
 - 0:07919e3d6c56
 
Update to reduce buffer sizes
Who changed what in which revision?
| User | Revision | Line number | New contents of line | 
|---|---|---|---|
| andrewbonney | 0:07919e3d6c56 | 1 | // expatpp | 
| andrewbonney | 0:07919e3d6c56 | 2 | #ifndef H_EXPATPP | 
| andrewbonney | 0:07919e3d6c56 | 3 | #define H_EXPATPP | 
| andrewbonney | 0:07919e3d6c56 | 4 | |
| andrewbonney | 0:07919e3d6c56 | 5 | #ifdef EXPATPP_COMPATIBLE_EXPAT12 // earlier versions of expat up to v1.2 | 
| andrewbonney | 0:07919e3d6c56 | 6 | #include "xmlparse.h" | 
| andrewbonney | 0:07919e3d6c56 | 7 | #else | 
| andrewbonney | 0:07919e3d6c56 | 8 | #include "expat.h" // since some version of expat moved to SourceForge | 
| andrewbonney | 0:07919e3d6c56 | 9 | #endif | 
| andrewbonney | 0:07919e3d6c56 | 10 | #include <stdio.h> | 
| andrewbonney | 0:07919e3d6c56 | 11 | #include <assert.h> | 
| andrewbonney | 0:07919e3d6c56 | 12 | |
| andrewbonney | 0:07919e3d6c56 | 13 | |
| andrewbonney | 0:07919e3d6c56 | 14 | /** | 
| andrewbonney | 0:07919e3d6c56 | 15 | \file expatpp.h | 
| andrewbonney | 0:07919e3d6c56 | 16 | Latest version 29-Dec-2002 compatible with expat 1.95.6 | 
| andrewbonney | 0:07919e3d6c56 | 17 | */ | 
| andrewbonney | 0:07919e3d6c56 | 18 | |
| andrewbonney | 0:07919e3d6c56 | 19 | /** | 
| andrewbonney | 0:07919e3d6c56 | 20 | expatpp follows a simple pattern for converting the semi-OOP callback design of | 
| andrewbonney | 0:07919e3d6c56 | 21 | expat into a true class which allows you to override virtual methods to supply | 
| andrewbonney | 0:07919e3d6c56 | 22 | callbacks. | 
| andrewbonney | 0:07919e3d6c56 | 23 | |
| andrewbonney | 0:07919e3d6c56 | 24 | \par USING expatpp | 
| andrewbonney | 0:07919e3d6c56 | 25 | see testexpatpp.cpp for a detailed example | 
| andrewbonney | 0:07919e3d6c56 | 26 | |
| andrewbonney | 0:07919e3d6c56 | 27 | 1) decide which callbacks you wish to use, eg: just startElement | 
| andrewbonney | 0:07919e3d6c56 | 28 | |
| andrewbonney | 0:07919e3d6c56 | 29 | 2) declare a subclass of expatpp, eg: | 
| andrewbonney | 0:07919e3d6c56 | 30 | class myExpat : public expatpp { | 
| andrewbonney | 0:07919e3d6c56 | 31 | virtual void startElement(const XML_Char* name, const XML_Char** atts); | 
| andrewbonney | 0:07919e3d6c56 | 32 | }; | 
| andrewbonney | 0:07919e3d6c56 | 33 | |
| andrewbonney | 0:07919e3d6c56 | 34 | 3) create an instance of your object and pass in a buffer to parse | 
| andrewbonney | 0:07919e3d6c56 | 35 | myExpat parser; | 
| andrewbonney | 0:07919e3d6c56 | 36 | parser.XML_Parse(buf, len, done) | 
| andrewbonney | 0:07919e3d6c56 | 37 | |
| andrewbonney | 0:07919e3d6c56 | 38 | |
| andrewbonney | 0:07919e3d6c56 | 39 | \par HOW IT WORKS | 
| andrewbonney | 0:07919e3d6c56 | 40 | The User Data which expat maintains is simply a pointer to an instance of your object. | 
| andrewbonney | 0:07919e3d6c56 | 41 | |
| andrewbonney | 0:07919e3d6c56 | 42 | Inline static functions are specified as the callbacks to expat. | 
| andrewbonney | 0:07919e3d6c56 | 43 | These static functions take the user data parameter returned from expat and cast it | 
| andrewbonney | 0:07919e3d6c56 | 44 | to a pointer to an expatpp object. | 
| andrewbonney | 0:07919e3d6c56 | 45 | |
| andrewbonney | 0:07919e3d6c56 | 46 | Using that typed pointer they then call the appropriate virtual method. | 
| andrewbonney | 0:07919e3d6c56 | 47 | |
| andrewbonney | 0:07919e3d6c56 | 48 | If you have overriden a given virtual method then your version will be called, otherwise | 
| andrewbonney | 0:07919e3d6c56 | 49 | the (empty) method in the base expatpp class is called. | 
| andrewbonney | 0:07919e3d6c56 | 50 | |
| andrewbonney | 0:07919e3d6c56 | 51 | \par Possible Efficiency Tactic | 
| andrewbonney | 0:07919e3d6c56 | 52 | For efficiency, you could provide your own constructor and set some of the callbacks | 
| andrewbonney | 0:07919e3d6c56 | 53 | to 0, so expat doesn't call the static functions. (untested idea). | 
| andrewbonney | 0:07919e3d6c56 | 54 | |
| andrewbonney | 0:07919e3d6c56 | 55 | \par Naming Conventions | 
| andrewbonney | 0:07919e3d6c56 | 56 | The virtual functions violate the usual AD Software convention of lowercase first letter | 
| andrewbonney | 0:07919e3d6c56 | 57 | for public methods but this was a late change to protected and too much user code out there. | 
| andrewbonney | 0:07919e3d6c56 | 58 | |
| andrewbonney | 0:07919e3d6c56 | 59 | |
| andrewbonney | 0:07919e3d6c56 | 60 | \todo Possibly implement some handling for XML_SetExternalEntityRefHandler which does NOT | 
| andrewbonney | 0:07919e3d6c56 | 61 | receive user data, just the parser, so can't use normal pattern for invoking virtual methods | 
| andrewbonney | 0:07919e3d6c56 | 62 | |
| andrewbonney | 0:07919e3d6c56 | 63 | \todo Possibly implement handling for XML_UnknownEncodingHandler. | 
| andrewbonney | 0:07919e3d6c56 | 64 | |
| andrewbonney | 0:07919e3d6c56 | 65 | \todo review design for nested calls - not happy that it is the right thing that they don't see | 
| andrewbonney | 0:07919e3d6c56 | 66 | their start and ending elements - makes it harder to unit test them in isolation. | 
| andrewbonney | 0:07919e3d6c56 | 67 | |
| andrewbonney | 0:07919e3d6c56 | 68 | \todo unit tests | 
| andrewbonney | 0:07919e3d6c56 | 69 | |
| andrewbonney | 0:07919e3d6c56 | 70 | \todo especially test abort mechanism | 
| andrewbonney | 0:07919e3d6c56 | 71 | |
| andrewbonney | 0:07919e3d6c56 | 72 | \todo reinstate copy constrution and assignment with child parser cleanup | 
| andrewbonney | 0:07919e3d6c56 | 73 | |
| andrewbonney | 0:07919e3d6c56 | 74 | \todo allow specification of encoding | 
| andrewbonney | 0:07919e3d6c56 | 75 | */ | 
| andrewbonney | 0:07919e3d6c56 | 76 | class expatpp { | 
| andrewbonney | 0:07919e3d6c56 | 77 | public: | 
| andrewbonney | 0:07919e3d6c56 | 78 | expatpp(bool createParser=true); | 
| andrewbonney | 0:07919e3d6c56 | 79 | virtual ~expatpp(); | 
| andrewbonney | 0:07919e3d6c56 | 80 | |
| andrewbonney | 0:07919e3d6c56 | 81 | operator XML_Parser() const; | 
| andrewbonney | 0:07919e3d6c56 | 82 | |
| andrewbonney | 0:07919e3d6c56 | 83 | protected: // callback virtuals should only be invoked through our Callback static functions | 
| andrewbonney | 0:07919e3d6c56 | 84 | bool emptyCharData(const XML_Char* s, int len); // utility often used in overridden charData | 
| andrewbonney | 0:07919e3d6c56 | 85 | |
| andrewbonney | 0:07919e3d6c56 | 86 | // overrideable callbacks | 
| andrewbonney | 0:07919e3d6c56 | 87 | virtual void startElement(const XML_Char* name, const XML_Char** atts); | 
| andrewbonney | 0:07919e3d6c56 | 88 | virtual void endElement(const XML_Char*); | 
| andrewbonney | 0:07919e3d6c56 | 89 | virtual void charData(const XML_Char*, int len); | 
| andrewbonney | 0:07919e3d6c56 | 90 | virtual void processingInstruction(const XML_Char* target, const XML_Char* data); | 
| andrewbonney | 0:07919e3d6c56 | 91 | virtual void defaultHandler(const XML_Char*, int len); | 
| andrewbonney | 0:07919e3d6c56 | 92 | virtual int notStandaloneHandler(); | 
| andrewbonney | 0:07919e3d6c56 | 93 | virtual void unparsedEntityDecl(const XML_Char* entityName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId, const XML_Char* notationName); | 
| andrewbonney | 0:07919e3d6c56 | 94 | virtual void notationDecl(const XML_Char* notationName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId); | 
| andrewbonney | 0:07919e3d6c56 | 95 | virtual void startNamespace(const XML_Char* prefix, const XML_Char* uri); | 
| andrewbonney | 0:07919e3d6c56 | 96 | virtual void endNamespace(const XML_Char*); | 
| andrewbonney | 0:07919e3d6c56 | 97 | /// \name Callbacks added to support expat 1.95.5 | 
| andrewbonney | 0:07919e3d6c56 | 98 | //@{ | 
| andrewbonney | 0:07919e3d6c56 | 99 | virtual void attlistDecl( | 
| andrewbonney | 0:07919e3d6c56 | 100 | const XML_Char *elname, | 
| andrewbonney | 0:07919e3d6c56 | 101 | const XML_Char *attname, | 
| andrewbonney | 0:07919e3d6c56 | 102 | const XML_Char *att_type, | 
| andrewbonney | 0:07919e3d6c56 | 103 | const XML_Char *dflt, | 
| andrewbonney | 0:07919e3d6c56 | 104 | int isrequired); | 
| andrewbonney | 0:07919e3d6c56 | 105 | virtual void endCdataSection(); | 
| andrewbonney | 0:07919e3d6c56 | 106 | virtual void endDoctypeDecl(); | 
| andrewbonney | 0:07919e3d6c56 | 107 | virtual void comment( const XML_Char *data); | 
| andrewbonney | 0:07919e3d6c56 | 108 | virtual void elementDecl( const XML_Char *name, XML_Content *model); | 
| andrewbonney | 0:07919e3d6c56 | 109 | virtual void entityDecl( | 
| andrewbonney | 0:07919e3d6c56 | 110 | const XML_Char *entityName, | 
| andrewbonney | 0:07919e3d6c56 | 111 | int is_parameter_entity, | 
| andrewbonney | 0:07919e3d6c56 | 112 | const XML_Char *value, | 
| andrewbonney | 0:07919e3d6c56 | 113 | int value_length, | 
| andrewbonney | 0:07919e3d6c56 | 114 | const XML_Char *base, | 
| andrewbonney | 0:07919e3d6c56 | 115 | const XML_Char *systemId, | 
| andrewbonney | 0:07919e3d6c56 | 116 | const XML_Char *publicId, | 
| andrewbonney | 0:07919e3d6c56 | 117 | const XML_Char *notationName); | 
| andrewbonney | 0:07919e3d6c56 | 118 | virtual void skippedEntity(const XML_Char *entityName, int is_parameter_entity); | 
| andrewbonney | 0:07919e3d6c56 | 119 | virtual void startCdataSection(); | 
| andrewbonney | 0:07919e3d6c56 | 120 | virtual void startDoctypeDecl(const XML_Char *doctypeName, | 
| andrewbonney | 0:07919e3d6c56 | 121 | const XML_Char *sysid, | 
| andrewbonney | 0:07919e3d6c56 | 122 | const XML_Char *pubid, | 
| andrewbonney | 0:07919e3d6c56 | 123 | int has_internal_subset); | 
| andrewbonney | 0:07919e3d6c56 | 124 | virtual void xmlDecl( const XML_Char *version, | 
| andrewbonney | 0:07919e3d6c56 | 125 | const XML_Char *encoding, | 
| andrewbonney | 0:07919e3d6c56 | 126 | int standalone); | 
| andrewbonney | 0:07919e3d6c56 | 127 | //@} | 
| andrewbonney | 0:07919e3d6c56 | 128 | |
| andrewbonney | 0:07919e3d6c56 | 129 | public: | 
| andrewbonney | 0:07919e3d6c56 | 130 | /// \name XML interfaces | 
| andrewbonney | 0:07919e3d6c56 | 131 | //@{ | 
| andrewbonney | 0:07919e3d6c56 | 132 | XML_Status XML_Parse(const char* buffer, int len, int isFinal); | 
| andrewbonney | 0:07919e3d6c56 | 133 | virtual XML_Status parseFile(FILE* inFile); | 
| andrewbonney | 0:07919e3d6c56 | 134 | virtual XML_Status parseString(const char*); | 
| andrewbonney | 0:07919e3d6c56 | 135 | XML_Error XML_GetErrorCode(); | 
| andrewbonney | 0:07919e3d6c56 | 136 | int XML_GetCurrentLineNumber(); | 
| andrewbonney | 0:07919e3d6c56 | 137 | int XML_GetCurrentColumnNumber(); | 
| andrewbonney | 0:07919e3d6c56 | 138 | //@} | 
| andrewbonney | 0:07919e3d6c56 | 139 | |
| andrewbonney | 0:07919e3d6c56 | 140 | protected: | 
| andrewbonney | 0:07919e3d6c56 | 141 | XML_Parser mParser; | 
| andrewbonney | 0:07919e3d6c56 | 142 | bool mHaveParsed; | 
| andrewbonney | 0:07919e3d6c56 | 143 | |
| andrewbonney | 0:07919e3d6c56 | 144 | /// \name overrideables to customise behaviour, must call parent | 
| andrewbonney | 0:07919e3d6c56 | 145 | //@{ | 
| andrewbonney | 0:07919e3d6c56 | 146 | virtual void ReleaseParser(); | 
| andrewbonney | 0:07919e3d6c56 | 147 | virtual void ResetParser(); | 
| andrewbonney | 0:07919e3d6c56 | 148 | virtual void SetupHandlers(); | 
| andrewbonney | 0:07919e3d6c56 | 149 | //@} | 
| andrewbonney | 0:07919e3d6c56 | 150 | |
| andrewbonney | 0:07919e3d6c56 | 151 | /** | 
| andrewbonney | 0:07919e3d6c56 | 152 | Override so subclass can react to an error causing exit from parse. | 
| andrewbonney | 0:07919e3d6c56 | 153 | rather than leave it for application code to check status. | 
| andrewbonney | 0:07919e3d6c56 | 154 | Useful point to insert logging to silently grab failed parses | 
| andrewbonney | 0:07919e3d6c56 | 155 | */ | 
| andrewbonney | 0:07919e3d6c56 | 156 | virtual void CheckFinalStatus(XML_Status) {}; | 
| andrewbonney | 0:07919e3d6c56 | 157 | |
| andrewbonney | 0:07919e3d6c56 | 158 | // static interface functions for callbacks | 
| andrewbonney | 0:07919e3d6c56 | 159 | public: | 
| andrewbonney | 0:07919e3d6c56 | 160 | static void startElementCallback(void *userData, const XML_Char* name, const XML_Char** atts); | 
| andrewbonney | 0:07919e3d6c56 | 161 | static void endElementCallback(void *userData, const XML_Char* name); | 
| andrewbonney | 0:07919e3d6c56 | 162 | static void startNamespaceCallback(void *userData, const XML_Char* prefix, const XML_Char* uri); | 
| andrewbonney | 0:07919e3d6c56 | 163 | static void endNamespaceCallback(void *userData, const XML_Char* prefix); | 
| andrewbonney | 0:07919e3d6c56 | 164 | static void charDataCallback(void *userData, const XML_Char* s, int len); | 
| andrewbonney | 0:07919e3d6c56 | 165 | static void processingInstructionCallback(void *userData, const XML_Char* target, const XML_Char* data); | 
| andrewbonney | 0:07919e3d6c56 | 166 | static void defaultHandlerCallback(void* userData, const XML_Char* s, int len); | 
| andrewbonney | 0:07919e3d6c56 | 167 | static int notStandaloneHandlerCallback(void* userData); | 
| andrewbonney | 0:07919e3d6c56 | 168 | static void unParsedEntityDeclCallback(void* userData, const XML_Char* entityName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId, const XML_Char* notationName); | 
| andrewbonney | 0:07919e3d6c56 | 169 | static void notationDeclCallback(void *userData, const XML_Char* notationName, const XML_Char* base, const XML_Char* systemId, const XML_Char* publicId); | 
| andrewbonney | 0:07919e3d6c56 | 170 | /// \name Callback interfacess added to support expat 1.95.5 | 
| andrewbonney | 0:07919e3d6c56 | 171 | //@{ | 
| andrewbonney | 0:07919e3d6c56 | 172 | static void attlistDeclCallback(void *userData, | 
| andrewbonney | 0:07919e3d6c56 | 173 | const XML_Char *elname, | 
| andrewbonney | 0:07919e3d6c56 | 174 | const XML_Char *attname, | 
| andrewbonney | 0:07919e3d6c56 | 175 | const XML_Char *att_type, | 
| andrewbonney | 0:07919e3d6c56 | 176 | const XML_Char *dflt, | 
| andrewbonney | 0:07919e3d6c56 | 177 | int isrequired); | 
| andrewbonney | 0:07919e3d6c56 | 178 | static void commentCallback(void *userData, const XML_Char *data); | 
| andrewbonney | 0:07919e3d6c56 | 179 | static void elementDeclCallback(void *userData, const XML_Char *name, XML_Content *model); | 
| andrewbonney | 0:07919e3d6c56 | 180 | static void endCdataSectionCallback(void *userData); | 
| andrewbonney | 0:07919e3d6c56 | 181 | static void endDoctypeDeclCallback(void *userData); | 
| andrewbonney | 0:07919e3d6c56 | 182 | static void entityDeclCallback(void *userData, | 
| andrewbonney | 0:07919e3d6c56 | 183 | const XML_Char *entityName, | 
| andrewbonney | 0:07919e3d6c56 | 184 | int is_parameter_entity, | 
| andrewbonney | 0:07919e3d6c56 | 185 | const XML_Char *value, | 
| andrewbonney | 0:07919e3d6c56 | 186 | int value_length, | 
| andrewbonney | 0:07919e3d6c56 | 187 | const XML_Char *base, | 
| andrewbonney | 0:07919e3d6c56 | 188 | const XML_Char *systemId, | 
| andrewbonney | 0:07919e3d6c56 | 189 | const XML_Char *publicId, | 
| andrewbonney | 0:07919e3d6c56 | 190 | const XML_Char *notationName); | 
| andrewbonney | 0:07919e3d6c56 | 191 | static void skippedEntityCallback(void *userData, const XML_Char *entityName, int is_parameter_entity); | 
| andrewbonney | 0:07919e3d6c56 | 192 | static void startCdataSectionCallback(void *userData); | 
| andrewbonney | 0:07919e3d6c56 | 193 | static void startDoctypeDeclCallback(void *userData, | 
| andrewbonney | 0:07919e3d6c56 | 194 | const XML_Char *doctypeName, | 
| andrewbonney | 0:07919e3d6c56 | 195 | const XML_Char *sysid, | 
| andrewbonney | 0:07919e3d6c56 | 196 | const XML_Char *pubid, | 
| andrewbonney | 0:07919e3d6c56 | 197 | int has_internal_subset); | 
| andrewbonney | 0:07919e3d6c56 | 198 | static void xmlDeclCallback(void *userData, const XML_Char *version, | 
| andrewbonney | 0:07919e3d6c56 | 199 | const XML_Char *encoding, | 
| andrewbonney | 0:07919e3d6c56 | 200 | int standalone); | 
| andrewbonney | 0:07919e3d6c56 | 201 | //@} | 
| andrewbonney | 0:07919e3d6c56 | 202 | |
| andrewbonney | 0:07919e3d6c56 | 203 | |
| andrewbonney | 0:07919e3d6c56 | 204 | // utilities | 
| andrewbonney | 0:07919e3d6c56 | 205 | static int skipWhiteSpace(const XML_Char*); | 
| andrewbonney | 0:07919e3d6c56 | 206 | static const XML_Char* getAttribute(const XML_Char *matchingName, const XML_Char **atts); | 
| andrewbonney | 0:07919e3d6c56 | 207 | static bool getIntegerAttribute(const XML_Char *matchingName, const XML_Char **atts, int& outAtt); | 
| andrewbonney | 0:07919e3d6c56 | 208 | static bool getDoubleAttribute(const XML_Char *matchingName, const XML_Char **atts, double& outAtt); | 
| andrewbonney | 0:07919e3d6c56 | 209 | }; | 
| andrewbonney | 0:07919e3d6c56 | 210 | |
| andrewbonney | 0:07919e3d6c56 | 211 | |
| andrewbonney | 0:07919e3d6c56 | 212 | /** | 
| andrewbonney | 0:07919e3d6c56 | 213 | subclass to support a hierarchy of parsers, in a sort of recursion or | 
| andrewbonney | 0:07919e3d6c56 | 214 | 'nesting' approach, where a top-level parser might create sub-parsers | 
| andrewbonney | 0:07919e3d6c56 | 215 | for part of a file. | 
| andrewbonney | 0:07919e3d6c56 | 216 | |
| andrewbonney | 0:07919e3d6c56 | 217 | The currently active child parser is owned (mOwnedChild) and is deleted | 
| andrewbonney | 0:07919e3d6c56 | 218 | by DeleteChild (invoked from the dtor) so error handling can propagate | 
| andrewbonney | 0:07919e3d6c56 | 219 | up the tree, closing parsers, without leaks. | 
| andrewbonney | 0:07919e3d6c56 | 220 | |
| andrewbonney | 0:07919e3d6c56 | 221 | \par Switching to sub-parsers | 
| andrewbonney | 0:07919e3d6c56 | 222 | You can transfer to a sub-parser with | 
| andrewbonney | 0:07919e3d6c56 | 223 | - new UserChildParser(this) // carries on using our parser, is self-deleting | 
| andrewbonney | 0:07919e3d6c56 | 224 | - switchToNewSubParser( someVar = new UserChildParser(this) ) // if want to get values back after end parsing | 
| andrewbonney | 0:07919e3d6c56 | 225 | |
| andrewbonney | 0:07919e3d6c56 | 226 | \warning You can accidentally invoke a new parser without it doing anything | 
| andrewbonney | 0:07919e3d6c56 | 227 | - new UserChildParser() // will be new top-level parser, nothing to do with our XML | 
| andrewbonney | 0:07919e3d6c56 | 228 | |
| andrewbonney | 0:07919e3d6c56 | 229 | \par Self-deletion | 
| andrewbonney | 0:07919e3d6c56 | 230 | If you transfer control to a sub-parser with just new UserChildParser(this) then | 
| andrewbonney | 0:07919e3d6c56 | 231 | it will be automatically self-deleting in its returnToParent method and | 
| andrewbonney | 0:07919e3d6c56 | 232 | will invoke OwnedChildOrphansItself to clear our mOwnedChild. | 
| andrewbonney | 0:07919e3d6c56 | 233 | |
| andrewbonney | 0:07919e3d6c56 | 234 | The reason for self-deletion being governed by a somewhat complex chain of | 
| andrewbonney | 0:07919e3d6c56 | 235 | calls rather than simply a boolean flag is because expatpp has been in use | 
| andrewbonney | 0:07919e3d6c56 | 236 | worldwide for many years and it was deemed too unfriendly to break code in | 
| andrewbonney | 0:07919e3d6c56 | 237 | a manner which could cause unwanted side effects - the current approach safely | 
| andrewbonney | 0:07919e3d6c56 | 238 | preserves self-deletion but also allows for expatpp to have parent parsers | 
| andrewbonney | 0:07919e3d6c56 | 239 | own and delete children, without compiling with different options. | 
| andrewbonney | 0:07919e3d6c56 | 240 | |
| andrewbonney | 0:07919e3d6c56 | 241 | \note | 
| andrewbonney | 0:07919e3d6c56 | 242 | If you invoke a sub-parser with switchToNewSubParser( new UserChildParser() ); | 
| andrewbonney | 0:07919e3d6c56 | 243 | then the user child parser will start with a new XML parser instance | 
| andrewbonney | 0:07919e3d6c56 | 244 | created by the expatpp ctor. This is safe but slightly wasteful of processing | 
| andrewbonney | 0:07919e3d6c56 | 245 | as the new parser will be discarded by BeAdopted(). | 
| andrewbonney | 0:07919e3d6c56 | 246 | |
| andrewbonney | 0:07919e3d6c56 | 247 | \par Switching to child and explicitly deleting | 
| andrewbonney | 0:07919e3d6c56 | 248 | switchToNewSubParser( somevar = new UserChildParser(this) ) allows you to get values | 
| andrewbonney | 0:07919e3d6c56 | 249 | back out of the child parser, in the context of the parent, eg: | 
| andrewbonney | 0:07919e3d6c56 | 250 | |
| andrewbonney | 0:07919e3d6c56 | 251 | \verbatim | 
| andrewbonney | 0:07919e3d6c56 | 252 | |
| andrewbonney | 0:07919e3d6c56 | 253 | void MultiFilterParser::startElement(const XML_Char* name, const XML_Char **atts) | 
| andrewbonney | 0:07919e3d6c56 | 254 | { | 
| andrewbonney | 0:07919e3d6c56 | 255 | if(strcmp(name,"FilterRequest")==0) { | 
| andrewbonney | 0:07919e3d6c56 | 256 | switchToNewSubParser( | 
| andrewbonney | 0:07919e3d6c56 | 257 | mCurrentFilterParser = new FilterRequestParser(this, atts) | 
| andrewbonney | 0:07919e3d6c56 | 258 | ); // we own and will have to explicitly delete | 
| andrewbonney | 0:07919e3d6c56 | 259 | ... | 
| andrewbonney | 0:07919e3d6c56 | 260 | } | 
| andrewbonney | 0:07919e3d6c56 | 261 | |
| andrewbonney | 0:07919e3d6c56 | 262 | void MultiFilterParser::endElement(const XML_Char *name) | 
| andrewbonney | 0:07919e3d6c56 | 263 | { | 
| andrewbonney | 0:07919e3d6c56 | 264 | if(strcmp(name,"FilterRequest")==0) { | 
| andrewbonney | 0:07919e3d6c56 | 265 | assert(mCurrentFilterParser); | 
| andrewbonney | 0:07919e3d6c56 | 266 | FilterClause* newClause = mCurrentFilterParser->orphanBuiltClause(); // retrieve data built by sub-parser | 
| andrewbonney | 0:07919e3d6c56 | 267 | ... | 
| andrewbonney | 0:07919e3d6c56 | 268 | mCurrentFilterParser = 0; | 
| andrewbonney | 0:07919e3d6c56 | 269 | DeleteChild(); | 
| andrewbonney | 0:07919e3d6c56 | 270 | } | 
| andrewbonney | 0:07919e3d6c56 | 271 | } | 
| andrewbonney | 0:07919e3d6c56 | 272 | \endverbatim | 
| andrewbonney | 0:07919e3d6c56 | 273 | */ | 
| andrewbonney | 0:07919e3d6c56 | 274 | class expatppNesting : public expatpp { | 
| andrewbonney | 0:07919e3d6c56 | 275 | |
| andrewbonney | 0:07919e3d6c56 | 276 | public: | 
| andrewbonney | 0:07919e3d6c56 | 277 | expatppNesting(expatppNesting* parent=0); ///< NOT a copy ctor!! this is a recursive situation | 
| andrewbonney | 0:07919e3d6c56 | 278 | virtual ~expatppNesting(); | 
| andrewbonney | 0:07919e3d6c56 | 279 | |
| andrewbonney | 0:07919e3d6c56 | 280 | void switchToNewSubParser( expatppNesting* pAdoptedChild ); | 
| andrewbonney | 0:07919e3d6c56 | 281 | expatppNesting* returnToParent(); | 
| andrewbonney | 0:07919e3d6c56 | 282 | |
| andrewbonney | 0:07919e3d6c56 | 283 | protected: | 
| andrewbonney | 0:07919e3d6c56 | 284 | void BeAdopted(expatppNesting* adoptingParent); | 
| andrewbonney | 0:07919e3d6c56 | 285 | void OwnedChildOrphansItself(expatppNesting* callingChild); | 
| andrewbonney | 0:07919e3d6c56 | 286 | void RegisterWithParentXMLParser(); | 
| andrewbonney | 0:07919e3d6c56 | 287 | virtual void AdoptChild(expatppNesting* adoptingChild); | 
| andrewbonney | 0:07919e3d6c56 | 288 | virtual void DeleteChild(); | 
| andrewbonney | 0:07919e3d6c56 | 289 | |
| andrewbonney | 0:07919e3d6c56 | 290 | int mDepth; | 
| andrewbonney | 0:07919e3d6c56 | 291 | bool mSelfDeleting; ///< only valid if mParent not null | 
| andrewbonney | 0:07919e3d6c56 | 292 | expatppNesting* mParent; ///< may be null the parent owns this object | 
| andrewbonney | 0:07919e3d6c56 | 293 | expatppNesting* mOwnedChild; ///< owned, optional currently active child (auto_ptr not used to avoid STL dependency) | 
| andrewbonney | 0:07919e3d6c56 | 294 | |
| andrewbonney | 0:07919e3d6c56 | 295 | public: | 
| andrewbonney | 0:07919e3d6c56 | 296 | /// \name interface functions for callbacks | 
| andrewbonney | 0:07919e3d6c56 | 297 | //@{ | 
| andrewbonney | 0:07919e3d6c56 | 298 | static void nestedStartElementCallback(void* userData, const XML_Char* name, const XML_Char** atts); | 
| andrewbonney | 0:07919e3d6c56 | 299 | static void nestedEndElementCallback(void* userData, const XML_Char* name); | 
| andrewbonney | 0:07919e3d6c56 | 300 | //@} | 
| andrewbonney | 0:07919e3d6c56 | 301 | |
| andrewbonney | 0:07919e3d6c56 | 302 | |
| andrewbonney | 0:07919e3d6c56 | 303 | /// \name overrideables to customise behaviour, must call parent | 
| andrewbonney | 0:07919e3d6c56 | 304 | //@{ | 
| andrewbonney | 0:07919e3d6c56 | 305 | virtual void SetupHandlers(); | 
| andrewbonney | 0:07919e3d6c56 | 306 | //@} | 
| andrewbonney | 0:07919e3d6c56 | 307 | |
| andrewbonney | 0:07919e3d6c56 | 308 | private: | 
| andrewbonney | 0:07919e3d6c56 | 309 | // Forbid copy-construction and assignment, to prevent double-deletion of mOwnedChild | 
| andrewbonney | 0:07919e3d6c56 | 310 | expatppNesting( const expatppNesting & ); | 
| andrewbonney | 0:07919e3d6c56 | 311 | expatppNesting & operator=( const expatppNesting & ); | 
| andrewbonney | 0:07919e3d6c56 | 312 | }; | 
| andrewbonney | 0:07919e3d6c56 | 313 | |
| andrewbonney | 0:07919e3d6c56 | 314 | |
| andrewbonney | 0:07919e3d6c56 | 315 | // inlines | 
| andrewbonney | 0:07919e3d6c56 | 316 | |
| andrewbonney | 0:07919e3d6c56 | 317 | // ------------------------------------------------------- | 
| andrewbonney | 0:07919e3d6c56 | 318 | // e x p a t p p | 
| andrewbonney | 0:07919e3d6c56 | 319 | // ------------------------------------------------------- | 
| andrewbonney | 0:07919e3d6c56 | 320 | inline | 
| andrewbonney | 0:07919e3d6c56 | 321 | expatpp::operator XML_Parser() const | 
| andrewbonney | 0:07919e3d6c56 | 322 | { | 
| andrewbonney | 0:07919e3d6c56 | 323 | return mParser; | 
| andrewbonney | 0:07919e3d6c56 | 324 | } | 
| andrewbonney | 0:07919e3d6c56 | 325 | |
| andrewbonney | 0:07919e3d6c56 | 326 | |
| andrewbonney | 0:07919e3d6c56 | 327 | // ------------------------------------------------------- | 
| andrewbonney | 0:07919e3d6c56 | 328 | // e x p a t p p N e s t i n g | 
| andrewbonney | 0:07919e3d6c56 | 329 | // ------------------------------------------------------- | 
| andrewbonney | 0:07919e3d6c56 | 330 | inline void | 
| andrewbonney | 0:07919e3d6c56 | 331 | expatppNesting::OwnedChildOrphansItself(expatppNesting* callingChild) | 
| andrewbonney | 0:07919e3d6c56 | 332 | { | 
| andrewbonney | 0:07919e3d6c56 | 333 | assert(callingChild==mOwnedChild); | 
| andrewbonney | 0:07919e3d6c56 | 334 | mOwnedChild = 0; | 
| andrewbonney | 0:07919e3d6c56 | 335 | } | 
| andrewbonney | 0:07919e3d6c56 | 336 | |
| andrewbonney | 0:07919e3d6c56 | 337 | |
| andrewbonney | 0:07919e3d6c56 | 338 | |
| andrewbonney | 0:07919e3d6c56 | 339 | #endif // H_EXPATPP |