In this sample code the Main.p exercise callbacks functionality against the SAX-READER object that reads the XML data in the familytree.xml file. The callback event handlers for the tokens encountered are implemented in the callbackclass.cls file. The schema that defines the data in the XML file is contained in the familytree.dtd file.

Main.p

VAR HANDLE hParser.
VAR callbackclass callbackObj.

CREATE SAX-READER hParser.
callbackObj = NEW callbackclass().
hParser:SCHEMA-PATH = ".".
hParser:SET-INPUT-SOURCE("FILE", "familytree.xml").

hParser:EVENT-HANDLER-OBJECT = callbackObj.

/* Initialize the parse */
hParser:SAX-PARSE().

DELETE OBJECT hParser.
callbackclass.cls
/*Enter your code here*/
/*************************************************************************
    Progname    : callbackclass.cls
    Description : This class contains methods for all 15 callback tokens
                  for the SAX-Reader Object
*************************************************************************/
ROUTINE-LEVEL ON ERROR UNDO, THROW.

CLASS callbackclass:

   /**********************************************************
     StartDocument method expects no parameters
   **********************************************************/
   METHOD PUBLIC void StartDocument():
       MESSAGE "Callback Method: StartDocument".
       MESSAGE "*****************************************".
   END METHOD.
   /**********************************************************
     StartDocument overloads
   **********************************************************/
   METHOD PUBLIC void StartDocument(INPUT vChar AS CHARACTER):
       MESSAGE "WRONG Callback Method OVERLOADED CHAR: StartDocument" .
       MESSAGE "*****************************************".
   END METHOD.
   METHOD PUBLIC void StartDocument(INPUT vInt AS INTEGER):
       MESSAGE "WRONG Callback Method OVERLOADED INT: StartDocument" .
       MESSAGE "*****************************************".
   END METHOD.
   METHOD PUBLIC void StartDocument(INPUT vChar AS CHARACTER,
                                    INPUT vInt AS INTEGER):
       MESSAGE "WRONG Callback Method OVERLOADED CHAR/INT: StartDocument" .
       MESSAGE "*****************************************".
   END METHOD.

   /**********************************************************
     EndDocument method expects no parameters
   **********************************************************/
   METHOD PUBLIC void EndDocument():
       MESSAGE "Callback Method: EndDocument".
       MESSAGE "*****************************************".
   END METHOD.
   /**********************************************************
     EndDocument overloads
   **********************************************************/
   METHOD PUBLIC void EndDocument(INPUT vChar AS CHARACTER):
       MESSAGE "WRONG Callback Method OVERLOADED CHAR: EndDocument".
       MESSAGE "*****************************************".
   END METHOD.
   METHOD PUBLIC void EndDocument(INPUT vInt AS INTEGER):
       MESSAGE "WRONG Callback Method OVERLOADED INT: EndDocument".
       MESSAGE "*****************************************".
   END METHOD.
   METHOD PUBLIC void EndDocument(INPUT vChar AS CHARACTER,
                                  INPUT vInt AS INTEGER):
       MESSAGE "WRONG Callback Method OVERLOADED CHAR/INT: EndDocument".
       MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void ResolveEntity(INPUT publicID AS CHAR,
                                    INPUT systemID AS CHAR,
                                    OUTPUT filePath AS CHAR,
                                    OUTPUT memPointer as memptr):
          MESSAGE "Callback Method: ResolveEntity"
          SKIP
          "publicID = " publicID
          SKIP
          "systemID = " systemID.
          MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void ProcessingInstruction(INPUT target AS CHAR,
                                            INPUT data AS CHAR):
          MESSAGE "Callback Method: ProcessingInstruction"
              SKIP
              "target = " target
              SKIP
              "data = " data.
          MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void UnparsedEntityDecl(INPUT name AS CHAR,
                                         INPUT publicID AS CHAR,
                                         INPUT systemID AS CHAR,
                                         INPUT notationName AS CHAR):
          MESSAGE "Callback Method: UnparsedEntityDecl"
              SKIP
              "name = " NAME
              SKIP
              "publicID = " publicID
              SKIP
              "systemID = " systemID
              SKIP
              "notationName = " notationName.
          MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void NotationDecl(INPUT name AS CHAR,
                                   INPUT publicID AS CHAR,
                                   INPUT systemID AS CHAR):
       MESSAGE "Callback Method: NotationDecl"
       SKIP
       "name = " NAME
       SKIP
       "publicID = " publicID
       SKIP
       "systemID = " systemID.
       MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void StartElement(INPUT namespaceURI AS CHARACTER,
                                   INPUT localname AS CHARACTER,
                                   INPUT qname AS CHARACTER,
                                   INPUT hattributes AS HANDLE):

      MESSAGE "Callback Method: StartElement"
           SKIP
           "namespaceURI = " namespaceURI
           SKIP
           "localname = " localname
           SKIP
           "qname = " qname.

      IF hattributes:num-items > 0 THEN
      DO:
          DEF VAR i AS INT64.
          DEF VAR thename AS CHAR.
          DEF VAR theqname AS CHAR.
          DEF VAR theuri AS CHAR FORMAT "x(30)".
          DEF VAR thetype AS CHAR.
          DEF VAR thevalue AS CHAR.

          MESSAGE "************".
          DO i = 1 TO hattributes:num-items:
             thename = hattributes:get-localname-by-index(i).
             MESSAGE "localname by index = " thename.
             theqname = hattributes:get-qname-by-index(i).
             MESSAGE "qname by index = " theqname.
             thevalue = hattributes:get-value-by-index(i).
             MESSAGE "value by index = " thevalue.
             thetype = hattributes:get-type-by-index(i).
             MESSAGE "type by index = " thetype.
             theuri = hattributes:get-uri-by-index(i).
             MESSAGE "uri by index = " theuri.
             MESSAGE "************".
           END.
      END.
      MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void Characters(INPUT charData as longchar,
                                 INPUT charLength AS INTEGER):
      DEF VAR tempData AS CHAR.
      tempData = charData.
      MESSAGE "Callback Method: Characters"
      SKIP
      "charData = " trim(tempData).
      MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void EndElement(INPUT namespaceURI AS CHAR,
                                 INPUT localname AS CHAR,
                                 INPUT qname AS CHAR):
       MESSAGE "Callback Method: EndElement"
           SKIP
           "namespaceURI = " namespaceURI
           SKIP
           "localname = " localname
           SKIP
           "qname = " qname.
       MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void IgnorableWhitespace(INPUT charData AS CHAR,
                                          INPUT charLenght AS INTEGER):
       MESSAGE "Callback Method: IgnorableWhitespace".
       MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void StartPrefixMapping(INPUT prefix AS CHAR,
                                         INPUT uri AS CHAR):
       MESSAGE "Callback Method: StartPrefixMapping"
       SKIP
       "prefix = " prefix
       SKIP
       "uri = " uri.
       MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void EndPrefixMapping(INPUT prefix AS CHAR):
       MESSAGE "Callback Method: EndPrefixMapping"
       SKIP
       "prefix = " prefix.
       MESSAGE "*****************************************".
   END METHOD.

   /* Error Handler callbacks */
   METHOD PUBLIC void Warning(INPUT errMESSAGE AS CHAR):

       MESSAGE "Callback Method: Warning".
        ErrorProcessing (errMessage).
       MESSAGE "*****************************************".
   END METHOD.

   METHOD PUBLIC void Error(INPUT errMessage AS CHAR):

       MESSAGE "Callback Method: Error".
        ErrorProcessing (errMessage).
       MESSAGE  "*****************************************".
   END METHOD.

   METHOD PUBLIC void FatalError(INPUT errMessage AS CHAR):

       MESSAGE "Callback Method: FatalError".
        ErrorProcessing (errMessage).
       MESSAGE "*****************************************".
   END METHOD.

   /* Internal method */
   METHOD PUBLIC static void ErrorProcessing(INPUT errorMsg AS CHAR):

       MESSAGE
           "Error Message = " errorMsg
           SKIP
           "lineNumber = " STRING(SELF:LOCATOR-LINE-NUMBER)
           SKIP
           "columnNumber = " STRING(SELF:LOCATOR-COLUMN-NUMBER)
           .
  END METHOD.
END CLASS.

familytree.dtd

<?xml version='1.0' encoding='UTF-8' ?>
<!ELEMENT familytree (person*)> 		 
<!ELEMENT person ( person-num, englishname+, parent+, spouse*, bio?, nickname*, photo*)>     
<!ELEMENT person-num EMPTY>
<!ATTLIST person-num   
	pid 		ID  	#REQUIRED   
	birthdate 	CDATA	#REQUIRED
	sex		(M|F) #REQUIRED>
<!ELEMENT englishname (name)>
<!ELEMENT name (firstname+, middlename*, lastname+)>
<!ELEMENT firstname (#PCDATA)>
<!ELEMENT middlename (#PCDATA)>
<!ELEMENT lastname (#PCDATA)>
<!ELEMENT parent (name)>
<!ELEMENT spouse (name)>
<!ELEMENT nickname (#PCDATA|firstname)*>
<!ELEMENT bio ANY>
<!ENTITY pic SYSTEM "mickey.jpg" NDATA jpg>
<!NOTATION jpg SYSTEM "/usr1/images">
<!ELEMENT photo EMPTY>
<!ATTLIST photo
	picture	ENTITY  	#IMPLIED>
familytree.xml
<?xml version="1.0"?>
<?hello goodbye?>
<!DOCTYPE familytree SYSTEM "familytree.dtd">
<!--  This document will have lots of whitespace   -->
<familytree>
	<person>
		<person-num pid="one" birthdate="June 8, 1932" sex="M"/>
		<englishname><name>
			<firstname>Michael</firstname>
			<middlename>J.</middlename>
			<lastname>Mouse</lastname>
		</name></englishname>
		<parent><name>
			<firstname>Papa</firstname>
			<lastname>Mouse</lastname>
		</name></parent>
		<parent><name>
			<firstname>Mama</firstname>
			<middlename>Annette</middlename>
			<middlename>Betty</middlename>
			<middlename>Chipmunk</middlename>
			<lastname>Mouse</lastname>
		</name></parent>
		<nickname>Mickey</nickname>
		<nickname>
			<firstname>M Mouse</firstname>
		</nickname>
		<photo  picture="pic"/>
	</person>
</familytree>