SAX/C++: First interface draft

James Clark jjc at jclark.com
Fri Dec 3 04:49:49 GMT 1999


In Java, everything in SAX is an interface. The way to do an interface
in C++ is to use a class where all members (except possibly a virtual
destructor) are abstract (ie defined as = 0).  This provides the maximum
flexibility and insulation. The only good reason not to do an interface
is if it were necessary and possible to inline some method calls for
performance.  I think this this applies here: certainly there's no
performance need to inline method calls to something like InputSource.

One interesting issue is whether to provide a virtual destructor.  I
think the safest solution is not to provide a virtual destructor but
instead to declare but not define a private operator delete.  This makes
it a compile time error to do:

  DTDHandler *p;
  // ...
  delete p;

Given the policy on object ownership there's never any need to do that:
only the creator of an object can delete it and the creator always has a
pointer to the concrete subclass which will provide a way to release the
object.

It also has the nice property that there is no .cpp file associated with
the SAX interface and no SAX library that has to be compiled or linked
with.  It would be a completely pure interface.

Here's another draft, with this change and a few other minor changes;

- use int not size_t (Lakos has a whole section on why unsigned in
interfaces is usually a bad idea)
- use a SAXString typedef for zero-terminated arrays
- don't use (void) for empty argument lists
- use iosfwd not istream as the header file
- use characters not SAXCharacters as the method name on DocumentHandler
- use a const char * arg for Parser::setLocale; I think that's the best
you can do portably; Standard C++ allows locales to be identifier by
name
- add Locator
- change resolveEntity to avoid transfer of ownership as suggested in my
previous message
- solve the UTF-8/UTF-16 problem by having two namespaces: a SAX_UTF8
and a SAX_UTF16 namespace (since you're using std::istream, you are
assuming compiler support for namespaces); this will work nicely with
namespace aliases (eg namespace SAX = SAX_UTF8).

Discussion points:

- Would it be better to typedef SAXString to the Standard C++ string
class (ie std::basic_string<SAXChar>)?

James

Here's SAX.h:

#ifndef __SAX_HXX
#define __SAX_HXX

// Forward declarations of std::istream
#include <iosfwd>

namespace SAX_UTF8 {

  typedef char SAXChar;
  // A 0 terminated array of SAXChars.
  typedef const char *SAXString;
#include "SAXDecl.h"

}

namespace SAX_UTF16 {

  typedef unsigned short SAXChar;
  // A 0 terminated array of SAXChars.
  typedef const unsigned short *SAXString;
#include "SAXDecl.h"

}

#endif

And here's SAXDecl.h:

class InputSource
{
public:
  virtual SAXString getPublicId () const = 0;
  virtual void setPublicId (SAXString publicId) = 0;

  virtual SAXString getSystemId () const = 0;
  virtual void setSystemId (SAXString systemId) = 0;

  virtual std::istream * getInputStream () const = 0;
  virtual void setInputStream (std::istream * in) = 0;
private:
  void operator delete (void *);
};


class AttributeList
{
public:
  virtual int getLength () const = 0;

  virtual SAXString getName (int pos) const = 0;
  virtual SAXString getType (int pos) const = 0;
  virtual SAXString getValue (int pos) const = 0;

  virtual SAXString getType (SAXString name) const = 0;
  virtual SAXString getValue (SAXString name) const = 0;
private:
  void operator delete (void *);
};


class SAXException
{
public:
  virtual SAXString getMessage () const = 0;
private:
  void operator delete (void *);
};


class SAXParseException : public SAXException
{
public:
  virtual SAXString getPublicId () const = 0;
  virtual SAXString getSystemId () const = 0;
  virtual int getLineNumber () const = 0;
  virtual int getColumnNumber () const = 0;
private:
  void operator delete (void *);
};


class EntityResolver
{
public:
  virtual void resolveEntity (SAXString publicId,
			      SAXString systemId,
			      InputSource &) = 0;
private:
  void operator delete (void *);
};


class DTDHandler
{
public:
  virtual void notationDecl (SAXString name,
			     SAXString publicId,
			     SAXString systemId) = 0;
  virtual void unparsedEntityDecl (SAXString name,
				   SAXString publicId,
				   SAXString systemId,
				   SAXString notationName) = 0;
private:
  void operator delete (void *);
};


class Locator
{
public:
  virtual SAXString getPublicId () const = 0;
  virtual SAXString getSystemId () const = 0;
  virtual int getLineNumber() const = 0;
  virtual int getColumnNumber() const = 0;
private:
  void operator delete (void *);
};

class DocumentHandler
{
public:
  virtual void setDocumentLocator (const Locator &locator) = 0;
  virtual void startDocument () = 0;
  virtual void endDocument () = 0;
  virtual void startElement (SAXString name, const AttributeList &atts)
= 0;
  virtual void endElement (SAXString name) = 0;
  virtual void characters (const SAXChar * ch, int length) = 0;
  virtual void ignorableWhitespace (const SAXChar * ch, int length) = 0;
  virtual void processingInstruction (SAXString target, SAXString data)
= 0;
private:
  void operator delete (void *);
};


class ErrorHandler
{
public:
  virtual void warning (const SAXParseException &e) = 0;
  virtual void error (const SAXParseException &e) = 0;
  virtual void fatalError (const SAXParseException &e) = 0;
private:
  void operator delete (void *);
};


class Parser
{
public:
  virtual void setLocale (const char *) = 0;
  virtual void setEntityResolver (EntityResolver &resolver) = 0;
  virtual void setDTDHandler (DTDHandler &handler) = 0;
  virtual void setDocumentHandler (DocumentHandler &handler) = 0;
  virtual void setErrorHandler (ErrorHandler &handler) = 0;

  virtual void parse (SAXString systemId) = 0;
  virtual void parse (const InputSource &input) = 0;
private:
  void operator delete (void *);
};

This also extends easily to doing a templated version:

template<class SAXChar, class SAXString>
class BASIC_SAX {
#include "SAXDecl.h"
};

James


xml-dev: A list for W3C XML Developers. To post, mailto:xml-dev at ic.ac.uk
Archived as: http://www.lists.ic.ac.uk/hypermail/xml-dev/ and on CD-ROM/ISBN 981-02-3594-1
To unsubscribe, mailto:majordomo at ic.ac.uk the following message;
unsubscribe xml-dev
To subscribe to the digests, mailto:majordomo at ic.ac.uk the following message;
subscribe xml-dev-digest
List coordinator, Henry Rzepa (mailto:rzepa at ic.ac.uk)





More information about the Xml-dev mailing list