Blog Archive

RPGLE XML Parser - XML-SAX and XML-INTO sample code Part 2


Click here to read from first Chapter

XML-SAX Events


During the SAX parsing of your XML document, several XML events will be passed to your XML-SAX handling procedure. To identify the events within your procedure, use the special names starting with *XML, for example *XML_START_ELEMENT. For most events, the handling procedure will be passed a value associated with the event. For example, for the *XML_START_ELEMENT event, the value is the name of the XML element.

Event Value
1. Events discovered before the first XML element
*XML_START_DOCUMENT Indicates that parsing has begun
*XML_VERSION_INFO The "version" value from the XML declaration
*XML_ENCODING_DECL The "encoding" value from the XML declaration
*XML_STANDALONE_DECL The "standalone" value from the XML declaration
*XML_DOCTYPE_DECL The value of the Document Type Declaration
2. Events related to XML elements
*XML_START_ELEMENT The name of the XML element that is starting
*XML_CHARS The value of the XML element
*XML_PREDEF_REF The value of a predefined reference
*XML_UCS2_REF The value of a UCS-2 reference
*XML_UNKNOWN_REF The name of an unknown entity reference
*XML_END_ELEMENT The name of the XML element that is ending
3. Events related to XML attributes
*XML_ATTR_NAME The name of the attribute
*XML_ATTR_CHARS The value of the attribute
*XML_ATTR_PREDEF_REF The value of a predefined reference
*XML_ATTR_UCS2_REF The value of a UCS-2 reference
*XML_UNKNOWN_ATTR_REF The name of an unknown entity reference
*XML_END_ATTR Indicates the end of the attribute
4. Events related to XML processing instructions
*XML_PI_TARGET The name of the target
*XML_PI_DATA The value of the data
5. Events related to XML CDATA sections
*XML_START_CDATA The beginning of the CDATA section
*XML_CHARS The value of the CDATA section
*XML_END_CDATA The end of the CDATA section
6. Other events
*XML_COMMENT The value of the XML comment
*XML_EXCEPTION Indicates that the parser discovered an error
*XML_END_DOCUMENT Indicates that parsing has ended

Read IBM document for more details

Demonstration of Events and Data

The first time you see it, it can be hard to understand the flow of events created by XML-SAX. Therefore use the following program that prints out each event as it occurs. You can step through this program in debug and see which events occur at which times. Or you can simply look at the printout it creates, which lists the events that occurred.

  H DFTACTGRP(*NO)
     FQSYSPRT   O    F  132        PRINTER

     D PrintMe         ds                  qualified
     D   name                        21a
     D   data                       111a

     D XML_Event_Name  PR            20A   varying
     D    event                      10i 0 value

     D xmlHandler      PR            10i 0
     D   ignore                       1a
     D   event                       10i 0 value
     D   string                        *   value
     D   stringLen                   20i 0 value
     D   exceptionId                 10i 0 value

     D XML             s            500a   varying
     D ignoreMe        s              1a
      /free
          XML = '<xmlTest>+
                 <name type="author">AS400 Sample Code/name>+
                 </xmlTest>';

          xml-sax %handler(xmlHandler: ignoreMe)
               %XML(XML: 'doc=string');

       *inlr = *on;

      /end-free

     P xmlHandler      B
     D xmlHandler      PI            10i 0
     D   ignore                       1a
     D   event                       10i 0 value
     D   string                        *   value
     D   stringLen                   20i 0 value
     D   exceptionId                 10i 0 value

     D value           s          65535a   based(String)
     D ucs2val         s          16363c   based(String)
     D dspstr          s             52a
      /free

         PrintMe.name = XML_Event_Name(event);
         PrintMe.data = *blanks;

         select;
         when string=*null or stringlen<1;
            // no string given...
         when stringlen>%size(value);
            PrintMe.data = '** string length invalid';
         other;
            PrintMe.data = %subst(value:1:stringlen);
         endsl;

         write QSYSPRT PrintMe;
         return 0;
      /end-free
     P                 E

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      *  Retrieve the event name for a given event number.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P XML_Event_Name  B
     D XML_Event_Name  PI            20A   varying
     D    event                      10i 0 value
      /free

         select;
         when event = *XML_START_DOCUMENT;
             return   'XML_START_DOCUMENT';
         when event = *XML_VERSION_INFO;
             return   'XML_VERSION_INFO';
         when event = *XML_ENCODING_DECL;
             return   'XML_ENCODING_DECL';
         when event = *XML_STANDALONE_DECL;
             return   'XML_STANDALONE_DECL';
         when event = *XML_DOCTYPE_DECL;
             return   'XML_DOCTYPE_DECL';
         when event = *XML_START_ELEMENT;
             return   'XML_START_ELEMENT';
         when event = *XML_CHARS;
             return   'XML_CHARS';
         when event = *XML_PREDEF_REF;
             return   'XML_PREDEF_REF';
         when event = *XML_UCS2_REF;
             return   'XML_UCS2_REF';
         when event = *XML_UNKNOWN_REF;
             return   'XML_UNKNOWN_REF';
         when event = *XML_END_ELEMENT;
             return   'XML_END_ELEMENT';
         when event = *XML_ATTR_NAME;
             return   'XML_ATTR_NAME';
         when event = *XML_ATTR_CHARS;
             return   'XML_ATTR_CHARS';
         when event = *XML_ATTR_PREDEF_REF;
             return   'XML_ATTR_PREDEF_REF';
         when event = *XML_ATTR_UCS2_REF;
             return   'XML_ATTR_UCS2_REF';
         when event = *XML_UNKNOWN_ATTR_REF;
             return   'XML_UNKNOWN_ATTR_REF';
         when event = *XML_END_ATTR;
             return   'XML_END_ATTR';
         when event = *XML_PI_TARGET;
             return   'XML_PI_TARGET';
         when event = *XML_PI_DATA;
             return   'XML_PI_DATA';
         when event = *XML_START_CDATA;
             return   'XML_START_CDATA';
         when event = *XML_END_CDATA;
             return   'XML_END_CDATA';
         when event = *XML_COMMENT;
             return   'XML_COMMENT';
         when event = *XML_EXCEPTION;
             return   'XML_EXCEPTION';
         when event = *XML_END_DOCUMENT;
             return   'XML_END_DOCUMENT';
         other;
             return   'UNKNOWN EVENT';
         endsl;
      /end-free
     P                 E

Note: It's important to understand that each time XML-SAX finds an event, it identifies the event by passing a number to your procedure. For example, each time the start of an XML element (often called "tag") is found, your handler is called with event=21. The 21 symbolizes the start of an XML element. RPG provides a named constant for each event number. In this example, *XML_START_ELEMENT is a named constant that has a value of 21. When you see code that says "if event = *XML_START_ELEMENT" it's equivalent to (but more self-documenting than) code that says "if event = 21."

In the preceding code, the XML_Event_Name() subprocedure returns a symbolic name for each event so you can print out which event has occurred. The rest of the code prints the data that was passed from XML-SAX to the handler procedure.When you run the preceding code, it will create a spooled file that contains the following:

XML_START_DOCUMENT                 
XML_START_ELEMENT    xmlTest       
XML_START_ELEMENT    name          
XML_ATTR_NAME        type          
XML_ATTR_CHARS       author        
XML_END_ATTR                       
XML_CHARS            AS400 Sample Code 
XML_END_ELEMENT      name          
XML_END_ELEMENT      xmlTest       
XML_END_DOCUMENT                 

By all means, give it a try. While you're at it, try the following:
  1. Try changing the XML string to different XML values and see what happens.
  2. Try putting an invalid XML document into the XML string, and notice how exceptions work.
  3. Try changing the XML-SAX opcode so that it reads data from an XML file in the IFS instead of a string in your program. 

XML = '/home/as400/SampleData.xml';
xml-sax %handler(xmlHandler: ignoreMe)
%XML(XML: 'doc=file');

Click here for next Chapter


Recommended Reading