[044716]: contrib / brl / b3p / expatpp / expatpp.h  Maximize  Restore  History

Download this file

359 lines (295 with data), 13.8 kB

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

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks