The XML-SAX opcode parses an XML document and calls a handler procedure once per parse event - start of document, start of an element, character data, end of an element, end of document - in document order. Unlike XML-INTO, it never populates a receiver variable; it is always driven by %HANDLER, and your handler decides what to do with each event.

xml-sax %handler(saxHandler : commArea) %xml(document : options);

The handler interface

The handler has a fixed interface dictated by IBM i: it returns a 4-byte integer and takes five parameters, in order:

dcl-pr saxHandler int(10);
  commArea     int(10);          // 1: communication area, by reference
  event        int(10) value;    // 2: event code (compare with the *XML_... constants)
  string       pointer value;    // 3: pointer to the event data
  stringLen    int(20) value;    // 4: length of the event data in bytes
  exceptionId  int(10) value;    // 5: parser exception id
end-pr;

The handler returns 0 to continue parsing; returning a non-zero value stops the parse.

Event constants

The core event special-value constants are recognized as their integer event codes and may be used anywhere an integer is allowed (typically a select over event):

Constant Event Data passed
*XML_START_DOCUMENT start of document none (length -1)
*XML_VERSION_INFO XML version from prolog the version string (e.g. "1.0")
*XML_ENCODING_DECL encoding= pseudo-attribute of the <?xml ?> declaration the encoding name (e.g. "UTF-8")
*XML_STANDALONE_DECL standalone= pseudo-attribute of the <?xml ?> declaration the standalone value ("yes" or "no")
*XML_DOCTYPE_DECL <!DOCTYPE ...> declaration the entire declaration text, delimiters included
*XML_START_ELEMENT start of an element the element name
*XML_ATTR_NAME attribute name the attribute name
*XML_ATTR_CHARS attribute value text the literal text between references in the value
*XML_ATTR_PREDEF_REF predefined entity ref inside an attribute value the resolved character, in the delivery CCSID
*XML_ATTR_UCS2_REF numeric character reference inside an attribute value the resolved character, always in UCS-2 (two bytes per BMP character)
*XML_UNKNOWN_ATTR_REF general/declared entity ref inside an attribute value the reference name (not resolved)
*XML_END_ATTR end of attribute none (length -1)
*XML_CHARS character data the text
*XML_PREDEF_REF predefined entity ref (&amp; &lt; &gt; &quot; &apos;) the resolved character, in the delivery CCSID
*XML_UCS2_REF numeric character reference (&#nn; or &#xhh;) the resolved character, always in UCS-2 (two bytes per BMP character)
*XML_UNKNOWN_REF general/declared entity ref in element content the reference name (not resolved)
*XML_END_ELEMENT end of an element the element name
*XML_END_DOCUMENT end of document none (length -1)
*XML_EXCEPTION parser exception -

Example

dcl-s xmlDoc varchar(500);
xmlDoc = '<order><item>Widget</item><qty>3</qty></order>';
xml-sax %handler(saxHandler : nLines) %xml(xmlDoc);

dcl-proc saxHandler;
  dcl-pi *n int(10);
    commArea    int(10);
    event       int(10) value;
    string      pointer value;
    stringLen   int(20) value;
    exceptionId int(10) value;
  end-pi;
  dcl-s data char(200) based(string);
  select;
    when event = *XML_START_ELEMENT;
      // ... %subst(data:1:stringLen) is the element name ...
    when event = *XML_CHARS;
      // ... %subst(data:1:stringLen) is the character data ...
    when event = *XML_END_ELEMENT;
      // ... element ended ...
  endsl;
  return 0;     // continue parsing
end-proc;

For the document above the handler is called in document order with: start document; start order; start item; chars Widget; end item; start qty; chars 3; end qty; end order; end document.

%XML options for XML-SAX: only doc and ccsid are valid for XML-SAX. Options that are specific to XML-INTO (case, trim, allowmissing, allowextra, path, countprefix) are rejected at compile time (TRN2401). Use doc=file to read the document from an IFS stream file (same semantics as XML-INTO doc=file).

Reference handling in element content: predefined entity references and numeric character references in element text are reported as their own events between *XML_CHARS segments, matching IBM i - a predefined entity as *XML_PREDEF_REF (resolved character in the delivery CCSID) and a numeric character reference as *XML_UCS2_REF (resolved character in UCS-2). For example <x>a&amp;b</x> yields chars a, *XML_PREDEF_REF &, chars b.

Reference handling in attribute values: references inside an attribute value are split the same way, between *XML_ATTR_CHARS segments - a predefined entity as *XML_ATTR_PREDEF_REF and a numeric character reference as *XML_ATTR_UCS2_REF (UCS-2). For example <e a="x&amp;y"> yields attr name a, attr chars x, *XML_ATTR_PREDEF_REF &, attr chars y, end attr. An attribute value with no references is a single *XML_ATTR_CHARS.

Unknown (general/declared) entity references: any entity reference that is not one of the five predefined entities and is not a numeric character reference is reported as *XML_UNKNOWN_REF in element content, or *XML_UNKNOWN_ATTR_REF inside an attribute value, carrying the reference name rather than a resolved value. This matches IBM i, whose parser does not process DTDs: an entity is reported by name whether it is declared in an internal DTD subset or entirely undeclared - an undeclared name is not a parse error. For example <e>t&foo;u</e> yields chars t, *XML_UNKNOWN_REF foo, chars u. The handler is responsible for interpreting the reference.

Prolog declaration events: the <?xml ?> declaration's pseudo-attributes are reported as their own events in document order - *XML_VERSION_INFO, then *XML_ENCODING_DECL (only if an encoding= is present), then *XML_STANDALONE_DECL (only if a standalone= is present) - after *XML_START_DOCUMENT and before the first *XML_START_ELEMENT. A bare <?xml version="1.0"?> yields only *XML_VERSION_INFO.

The DOCTYPE declaration: a <!DOCTYPE ...> declaration is reported as a *XML_DOCTYPE_DECL event carrying the entire declaration text - the only event whose data includes the delimiters - with an internal subset ([...]) passed through verbatim. It follows the prolog declaration events and precedes the first *XML_START_ELEMENT. The DTD's contents are never processed: an entity declared in the internal subset is still reported as *XML_UNKNOWN_REF by name, and the external subset is not loaded.

Supported events: the event set above covers document lifecycle, elements, attributes, predefined/numeric character references and unknown (declared/general) entity references in both element content and attribute values, the XML version, encoding, and standalone declarations, and the DOCTYPE declaration. CDATA-section boundaries are not surfaced; CDATA text is delivered as ordinary *XML_CHARS. The handler must declare exactly five parameters with the third a pointer (TRN3020, TRN3021).

An *XML_ name that is not on this list is a compile-time error (TRN2006), including the unsurfaced event class. It is never accepted as a character value: a name the compiler did not recognize would compare unequal to every event code, so the handler branch would silently never run.