CREATE SAX-ATTRIBUTES statement

Creates an instance of a SAX-attributes object and assigns its handle to the handle variable specified. Use this object to access and manage the attribute list for an XML element either being read or written with the SAX-reader or SAX-writer object.

Syntax

CREATE SAX-ATTRIBUTES handle [ IN WIDGET-POOL pool-name ] [ NO-ERROR ]
handle
Variable of type HANDLE which stores the handle of the new SAX-attributes object.
IN WIDGET-POOL pool-name
Specifies the widget pool where the AVM creates the new object. If you do not specify a widget pool, the AVM creates the object in the current default widget pool.
NO-ERROR
Suppresses ABL errors or error messages that would otherwise occur and diverts them to the ERROR-STATUS system handle. If an error occurs, the action of the statement is not done and execution continues with the next statement. If the statement fails, any persistent side-effects of the statement are backed out. If the statement includes an expression that contains other executable elements, like methods, the work performed by these elements may or may not be done, depending on the order the AVM resolves the expression elements and the occurrence of the error.

To check for errors after a statement that uses the NO-ERROR option:

  • Check the ERROR-STATUS:ERROR attribute to see if the AVM raised the ERROR condition.
  • Check if the ERROR-STATUS:NUM-MESSAGES attribute is greater than zero to see if the AVM generated error messages. ABL handle methods used in a block without a CATCH end block treat errors as warnings and do not raise ERROR, do not set the ERROR-STATUS:ERROR attribute, but do add messages to the ERROR-STATUS system handle. Therefore, this test is the better test for code using handle methods without CATCH end blocks. ABL handle methods used in a block with a CATCH end block raise ERROR and add messages to the error object generated by the AVM. In this case, the AVM does not update the ERROR-STATUS system handle.
  • Use ERROR-STATUS:GET-MESSAGE( message-num ) to retrieve a particular message, where message-num is 1 for the first message.

If the statement does not include the NO-ERROR option, you can use a CATCH end block to handle errors raised by the statement.

Some other important usage notes on the NO-ERROR option:

  • NO-ERROR does not suppress errors that raise the STOP or QUIT condition.
  • A CATCH statement, which introduces a CATCH end block, is analogous to a NO-ERROR option in that it also suppresses errors, but it does so for an entire block of code. It is different in that the error messages are contained in a class-based error object (generated by the AVM or explicitly thrown), as opposed to the ERROR-STATUS system handle. Also, if errors raised in the block are not handled by a compatible CATCH block, ON ERROR phrase, or UNDO statement, then the error is not suppressed, but handled with the default error processing for that block type.
  • When a statement contains the NO-ERROR option and resides in a block with a CATCH end block, the NO-ERROR option takes precedence over the CATCH block. That is, an error raised on the statement with the NO-ERROR option will not be handled by a compatible CATCH end block. The error is redirected to the ERROR-STATUS system handle as normal.
  • If an error object is thrown to a statement that includes the NO-ERROR option, then the information and messages in the error object will be used to set the ERROR-STATUS system handle. This interoperability feature is important for those integrating code that uses the traditional NO-ERROR technique with the newer, structured error handling that features error objects and CATCH end blocks.

In ABL, a SAX-attributes object can be automatically created and managed by the SAX parser, or programatically created and managed by you. Automatic SAX-attributes objects are created, populated, and destroyed during the scope of the startElement callback procedure. The startElement callback is called by the SAX-reader object each time the SAX parser encounters new XML element during a read operation. The SAX parser populates the SAX-attributes object, but you may interact with the object during the scope of the startElement callback procedure. For example, you may add elements, update elements, and remove elements from the SAX-attributes object.

At the conclusion of the callback, the SAX-attributes object is deleted and your access to the element list is lost. To save the XML attributes list, you would need to create another SAX-attributes object that is not tied to the scope of the startElement callback procedure. Then, from within the startElement callback, you would use the COPY-SAX-ATTRIBUTES( ) method on the new object and provide a handle to the automatically created SAX-attributes object.

Finally, you would likely pass the XML element and its attributes to a SAX-writer object to concurrently build a new XML document while reading the source XML document.

Example

The following code snippets assembled form one complete example of a concurrent XML read and write operation. The first snippet shows the main block of code:

DEFINE VARIABLE cFileRead  AS CHARACTER NO-UNDO INITIAL "custorders.xml".
DEFINE VARIABLE cFileWrite AS CHARACTER NO-UNDO INITIAL "custitems.xml".

DEFINE VARIABLE hReader AS HANDLE  NO-UNDO.
DEFINE VARIABLE hWriter AS HANDLE  NO-UNDO.
DEFINE VARIABLE hSaxAtt AS HANDLE  NO-UNDO.
DEFINE VARIABLE lok     AS LOGICAL NO-UNDO.

CREATE SAX-READER hReader.
CREATE SAX-WRITER hWriter.
CREATE SAX-ATTRIBUTES hSaxAtt.

/* Uses THIS-PROCEDURE as the SAX handler. All callbacks are below. */

lok = hReader:SET-INPUT-SOURCE("file", cFileRead).
lok = hWriter:SET-OUTPUT-DESTINATION("file", cFileWrite).

hReader:SAX-PARSE().
IF ERROR-STATUS:ERROR THEN DO:
  MESSAGE "Problem reading the XML file:" cFileRead.
  MESSAGE ERROR-STATUS:GET-MESSAGE(1).
END.
ELSE
  MESSAGE "XML file converted. Written to" cFileWrite.

DELETE OBJECT hReader.
DELETE OBJECT hWriter.
DELETE OBJECT hSaxAtt.

This snippet contains the callbacks for starting and ending a document read. Note that embedded in the steps of the read operation are the corresponding steps for a concurrent write operation:

/* SAX-reader callbacks below*/

/* Context controller */
DEFINE VARIABLE lWriteChar AS LOGICAL NO-UNDO.

PROCEDURE startdocument:
  ASSIGN
    hWriter:ENCODING = "utf-8"
    lok              = hWriter:START_DOCUMENT().
END PROCEDURE.

PROCEDURE enddocument:
  lok = hWriter:END-DOCUMENT().
END PROCEDURE.

The startElement callback does most of the processing. Depending on the values being read by SAX-reader, the callback decides what to write to the new XML document:

PROCEDURE startelement:
  DEFINE INPUT PARAMETER namespaceuri AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER localname    AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER qname        AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER attributes   AS HANDLE    NO-UNDO.

  CASE qname:
    WHEN "customer" THEN ASSIGN
      lWriteChar = FALSE
      lok        = hSaxAtt:COPY-SAX-ATTRIBUTES(attributes)
      lok        = hWriter:START-ELEMENT(qname).
    WHEN "name" THEN ASSIGN
      lWriteChar = TRUE
      lok        = hSaxAtt:REMOVE-ATTRIBUTE("id")
      lok        = hWriter:START-ELEMENT(qname, hSaxAtt).
    WHEN "order" THEN ASSIGN
      lWriteChar = FALSE
      lok        = hWriter:START-ELEMENT(qname).
    WHEN "item" THEN ASSIGN
      lWriteChar = FALSE
      lok        = hWriter:START-ELEMENT(qname)
      lok        = hWriter:WRITE-CHARACTERS
        (attributes:GET-VALUE-BY-QNAME("description"))
      lok        = hWriter:END-ELEMENT(qname).
    WHEN "custorders" THEN ASSIGN
      lWriteChar = FALSE
      lok        = hWriter:START-ELEMENT("custitems").
  END CASE.
END PROCEDURE.

The last snippet completes the set of callback procedures needed for this example:

PROCEDURE endelement:
  DEFINE INPUT PARAMETER namespaceuri AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER localname    AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER qname        AS CHARACTER NO-UNDO.

  IF qname = "customer" OR qname = "name" OR qname = "order" THEN
    lok = hWriter:END-ELEMENT(qname).

  IF qname = "custorders" THEN
    lok = hWriter:END-ELEMENT("custitems").
END PROCEDURE.

PROCEDURE characters:
  DEFINE INPUT PARAMETER chararray   AS LONGCHAR NO-UNDO.
  DEFINE INPUT PARAMETER arraylength AS INTEGER  NO-UNDO.

  IF lWriteChar THEN 
    lok = hWriter:WRITE-CHARACTERS(chararray).
END PROCEDURE.

See also

SAX-attributes object handle