SAX based XML parser

Dependents:   giken9_HTMLServer_Temp_Sample

Embed: (wiki syntax)

« Back to documentation index

expatppNesting Class Reference

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. More...

#include <expatpp.h>

Inherits expatpp.

Public Member Functions

 expatppNesting (expatppNesting *parent=0)
 NOT a copy ctor!! this is a recursive situation.
void switchToNewSubParser (expatppNesting *pAdoptedChild)
 User code (typically the startElement handler of user parsers derived from expatppNesting) may call switchToNewSubParser( new UserChildParser() ); to hand off the current document to a child parser that understands the next segment of XML.
expatppNestingreturnToParent ()
 If this is root parser, nestedEndElementCallback won't call returnToParent.
overrideables to customise behaviour, must call parent
virtual void SetupHandlers ()
 Call parent version then override same as in our ctor.
XML interfaces
XML_Status XML_Parse (const char *buffer, int len, int isFinal)
virtual XML_Status parseFile (FILE *inFile)
 Parse entire file, basically copy of the loop from the elements.c example.
virtual XML_Status parseString (const char *)
 Parse string which is assumed to be entire XML document.
XML_Error XML_GetErrorCode ()
int XML_GetCurrentLineNumber ()
int XML_GetCurrentColumnNumber ()

Static Public Member Functions

static const XML_Char * getAttribute (const XML_Char *matchingName, const XML_Char **atts)
 Iterate the paired attribute name/value until find a pair with matching name.
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)
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)
 If this is root parser, will never hit nestedEndElementCallback after closing element, except for when we call it.
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)

Protected Member Functions

void BeAdopted (expatppNesting *adoptingParent)
 Called by switchToNewSubParser to indicate a newly created child parser is now the currently active child for adoptingParent and the child isn't expected to be self deleting.
void RegisterWithParentXMLParser ()
 to use parent's underlying expat parser
virtual void AdoptChild (expatppNesting *adoptingChild)
 Invoked as a callback from a child ctor when we pass in a parent pointer.
virtual void DeleteChild ()
 Must use if you have adopted a child parser and want to dispose of it early.
virtual void CheckFinalStatus (XML_Status)
 Override so subclass can react to an error causing exit from parse.
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)
overrideables to customise behaviour, must call parent
virtual void ReleaseParser ()
 Provide single point that will call XML_ParserFree.
virtual void ResetParser ()
 Provide single point that will call XML_ParserReset.

Protected Attributes

bool mSelfDeleting
 only valid if mParent not null
expatppNestingmParent
 may be null the parent owns this object
expatppNestingmOwnedChild
 owned, optional currently active child (auto_ptr not used to avoid STL dependency)

Detailed Description

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.

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
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().
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:
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();
    }
}

Definition at line 274 of file expatpp.h.


Constructor & Destructor Documentation

expatppNesting ( expatppNesting parent = 0 )

NOT a copy ctor!! this is a recursive situation.

Parameters:
parentcan be null in which case this is root parser
Note:
The handlers set in here MUST be also set in SetupHandlers which is a virtual method invoked by expatpp::ResetParser. Otherwise you can have subtle bugs with a nested parser not properly returning after reusing a parser (nasty and found rapidly only via extensive unit tests and plentiful assertions!).

The assumption that is not obvious here is that if you want to use nested parsers, then your topmost parser must also be an expatppNesting subclass, NOT an expatpp subclass, because we need the nestedStartElementCallback and nestedEndElementCallback callbacks to override those in the expatpp ctor.

Definition at line 618 of file expatpp.cpp.


Member Function Documentation

void AdoptChild ( expatppNesting adoptingChild ) [protected, virtual]

Invoked as a callback from a child ctor when we pass in a parent pointer.

OR used from switchToNewSubParser, in which case it may be the 2nd time we're called for a given child (see scenarios in expatppNesting class comment).

Definition at line 673 of file expatpp.cpp.

void BeAdopted ( expatppNesting adoptingParent ) [protected]

Called by switchToNewSubParser to indicate a newly created child parser is now the currently active child for adoptingParent and the child isn't expected to be self deleting.

Normal code to create an owned child would be either switchToNewSubParser( new UserChildParser(this) ); where this is the currently active parser and you want to be deleting it, or new UserChildParser(this); to have a child parser self-delete

Important Safety Note
Copes with the situation of people forgetting to pass in the parent parser (and hence creating a new one by default) if invoked by switchToNewSubParser( new UserChildParser() ) by somewhat wastefully deleting the parser created in expatpp::expatpp by us being a root parser.

Definition at line 789 of file expatpp.cpp.

virtual void CheckFinalStatus ( XML_Status   ) [protected, virtual, inherited]

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

Definition at line 156 of file expatpp.h.

void DeleteChild (  ) [protected, virtual]

Must use if you have adopted a child parser and want to dispose of it early.

Definition at line 660 of file expatpp.cpp.

const XML_Char * getAttribute ( const XML_Char *  matchingName,
const XML_Char **  atts 
) [static, inherited]

Iterate the paired attribute name/value until find a pair with matching name.

Returns:
pointer to the value or null if not found.

Definition at line 341 of file expatpp.cpp.

bool getDoubleAttribute ( const XML_Char *  matchingName,
const XML_Char **  atts,
double &  outAtt 
) [static, inherited]

Definition at line 378 of file expatpp.cpp.

bool getIntegerAttribute ( const XML_Char *  matchingName,
const XML_Char **  atts,
int &  outAtt 
) [static, inherited]

Definition at line 358 of file expatpp.cpp.

void nestedEndElementCallback ( void *  userData,
const XML_Char *  name 
) [static]

If this is root parser, will never hit nestedEndElementCallback after closing element, except for when we call it.

Parameters:
userDatashould be non-nil except for specific case of ending root

Definition at line 750 of file expatpp.cpp.

XML_Status parseFile ( FILE *  inFile ) [virtual, inherited]

Parse entire file, basically copy of the loop from the elements.c example.

Definition at line 120 of file expatpp.cpp.

XML_Status parseString ( const char *  inString ) [virtual, inherited]

Parse string which is assumed to be entire XML document.

Written to stop stupid errors of being off by one in the string length causing wasted debugging time, such as:

    const char[] kSampleSettings = "<settings/>";
    const int sampleSize = sizeof(kSampleSettings)-1;  // unless you remember to subtract one here will get invalid token error
    if (!parser.XML_Parse(kSampleSettings, sampleSize, 1)) {

Definition at line 186 of file expatpp.cpp.

void RegisterWithParentXMLParser (  ) [protected]

to use parent's underlying expat parser

Definition at line 687 of file expatpp.cpp.

void ReleaseParser (  ) [protected, virtual, inherited]

Provide single point that will call XML_ParserFree.

Nothing else in this code should call XML_ParserFree!

Definition at line 80 of file expatpp.cpp.

void ResetParser (  ) [protected, virtual, inherited]

Provide single point that will call XML_ParserReset.

Guarded against trivial reset before use in case that breaks expat or creates overhead.

Definition at line 96 of file expatpp.cpp.

expatppNesting * returnToParent (  )

If this is root parser, nestedEndElementCallback won't call returnToParent.

Therefore it is safe to put parsers on the stack.

Definition at line 720 of file expatpp.cpp.

void SetupHandlers (  ) [virtual]

Call parent version then override same as in our ctor.

Reimplemented from expatpp.

Definition at line 650 of file expatpp.cpp.

void switchToNewSubParser ( expatppNesting pAdoptedChild )

User code (typically the startElement handler of user parsers derived from expatppNesting) may call switchToNewSubParser( new UserChildParser() ); to hand off the current document to a child parser that understands the next segment of XML.

Control will be returned to the original (parent) parser when the end of the child element is reached. In its lifetime a 'parent' parser may switch control to several child parsers (one at a time of course) as it moves through the document encoutering various types of child element.

A child to which older code (eg: OOFILE) has just switched control by new childParser(this) will be self-deleting and will clear our mOwnedChild in its dtor.

Definition at line 707 of file expatpp.cpp.


Field Documentation

owned, optional currently active child (auto_ptr not used to avoid STL dependency)

Definition at line 293 of file expatpp.h.

expatppNesting* mParent [protected]

may be null the parent owns this object

Definition at line 292 of file expatpp.h.

bool mSelfDeleting [protected]

only valid if mParent not null

Definition at line 291 of file expatpp.h.