SAX based XML parser
Dependents: giken9_HTMLServer_Temp_Sample
expatpp.h@0:07919e3d6c56, 2011-04-08 (annotated)
- Committer:
- andrewbonney
- Date:
- Fri Apr 08 09:18:41 2011 +0000
- Revision:
- 0:07919e3d6c56
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 |