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);
%handler(proc : commArea)names the handler procedure and a communication area passed to it (by reference) on every call.%xml(document : options)supplies the document (a string or an IFS file path withdoc=file) and parsing options. The(E)operation extender is accepted.
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;
- commArea - your own state, passed by reference, so the handler can accumulate results across events.
- event - the event code. Compare it against the event constants below.
- string / stringLen - a pointer to the event data and its byte length. Read the
data through a
BASEDvariable over the pointer, e.g.dcl-s data char(200) based(string); … %subst(data:1:stringLen). Events that carry no data (document start/end) pass a length of-1.stringLenis a byte count in the CCSID the data is delivered in: one byte per character by default (the single-byte job CCSID), or two bytes per character when theccsid=ucs2option is used - so the same five-character element name reports5by default and10underccsid=ucs2. - exceptionId - the parser exception id (reserved for exception handling).
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 (& < > " ') |
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
docandccsidare valid forXML-SAX. Options that are specific toXML-INTO(case,trim,allowmissing,allowextra,path,countprefix) are rejected at compile time (TRN2401). Usedoc=fileto read the document from an IFS stream file (same semantics asXML-INTOdoc=file).Reference handling in element content: predefined entity references and numeric character references in element text are reported as their own events between
*XML_CHARSsegments, 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&b</x>yields charsa,*XML_PREDEF_REF&, charsb.Reference handling in attribute values: references inside an attribute value are split the same way, between
*XML_ATTR_CHARSsegments - a predefined entity as*XML_ATTR_PREDEF_REFand a numeric character reference as*XML_ATTR_UCS2_REF(UCS-2). For example<e a="x&y">yields attr namea, attr charsx,*XML_ATTR_PREDEF_REF&, attr charsy, 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_REFin element content, or*XML_UNKNOWN_ATTR_REFinside 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 charst,*XML_UNKNOWN_REFfoo, charsu. 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 anencoding=is present), then*XML_STANDALONE_DECL(only if astandalone=is present) - after*XML_START_DOCUMENTand 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_DECLevent 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_REFby 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.