DEFINE VARIABLE hParser AS HANDLE NO-UNDO.
DEFINE VARIABLE hHandler AS HANDLE NO-UNDO. /* Create the SAX-READER object */ CREATE SAX-READER hParser. /* Run the persistent procedure that contains the callbacks */ RUN "i-sax2h.p" PERSISTENT SET hHandler. /* Give the SAX-READER the handle to the persistent procedure */ hParser:HANDLER = hHandler. /* Give the SAX-READER the info on the file to parse. This XML file does not use namespaces. */ hParser:SET-INPUT-SOURCE("FILE", "i-sax2.xml"). hParser:SAX-PARSE( ) NO-ERROR. /* By the time SAX-PARSE returns, the callbacks have been called as many times as necessary and we're done processing the XML document (or there was an error) */ IF ERROR-STATUS:ERROR THEN DO: IF ERROR-STATUS:NUM-MESSAGES > 0 THEN /* unable to begin the parse */ MESSAGE ERROR-STATUS:GET-MESSAGE(1) VIEW-AS ALERT-BOX. ELSE /* error detected in a callback */ MESSAGE RETURN-VALUE VIEW-AS ALERT-BOX. END. ELSE MESSAGE "Document parsed successfully" VIEW-AS ALERT-BOX. DELETE OBJECT hParser. DELETE PROCEDURE hHandler. |
<?xml version='1.0' ?>
<Customers> <Customer Name="Lift Line Skiing" Cust-num="1"> <Country>USA</Country> <Address>276 North Street</Address> <Address2></Address2> <City>Boston</City> <State>MA</State> <Postal-Code>02114</Postal-Code> <Contact>Gloria Shepley</Contact> <Phone>(617) 450-0087</Phone> <Sales-Rep>HXM</Sales-Rep> <Credit-Limit>66700</Credit-Limit> <Balance>42568</Balance> <Terms>Net30</Terms> <Discount>35</Discount> <Comments>This customer is on credit hold.</Comments> </Customer> <Customer Name="Hoops " Cust-num="3"> <Country>USA</Country> <Address>Suite 415</Address> <Address2>40 Grove St.</Address2> <City>Atlanta</City> <State>GA</State> <Postal-Code>02112</Postal-Code> <Contact>Michael Traitser</Contact> <Phone>(617) 355-1557</Phone> <Sales-Rep>HXM</Sales-Rep> <Credit-Limit>75000</Credit-Limit> <Balance>1199.95</Balance> <Terms>Net30</Terms> <Discount>10</Discount> <Comments>This customer is now OFF credit hold.</Comments> </Customer> </Customers> |
DEFINE VARIABLE hBuf AS HANDLE NO-UNDO.
DEFINE VARIABLE hDBFld AS HANDLE NO-UNDO. /* Variable in which to accumulate all the text data for one element coming in through potentially multiple calls (per element) to the Characters procedure */ DEFINE VARIABLE currentFieldValue AS CHARACTER NO-UNDO. /* Simple-minded state machine – the code makes minimal use of it, but it could easily be used to validate the structure of the document in this example. */ DEFINE VARIABLE iProcessingState AS INTEGER NO-UNDO. /* So we can create new records*/ DEFINE TEMP-TABLE ttCustomer LIKE Customer. &SCOPED-DEFINE READY-TO-START 1 &SCOPED-DEFINE GETTING-RECORDS 2 &SCOPED-DEFINE GETTING-FIELDS 3 &SCOPED-DEFINE DONE 4 hBuf = BUFFER ttCustomer:HANDLE. PROCEDURE StartDocument: iProcessingState = {&READY-TO-START}. END PROCEDURE. 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. IF qName = "Customers" THEN iProcessingState = {&GETTING-RECORDS}. ELSE IF qName = "Customer" THEN DO: /* Starting a new customer, so create the record */ CREATE ttCustomer. ASSIGN /* Get the fields that are in the XML doc as attributes */ ttCustomer.CustNum = INTEGER(attributes:GET-VALUE-BY-QNAME("CustNum")) ttCustomer.Name = attributes:GET-VALUE-BY-QNAME( "Name" ) iProcessingState = {&GETTING-FIELDS}. END. ELSE IF iProcessingState = {&GETTING-FIELDS} THEN DO: /* Get a handle to the field whose name corresponds to the element name */ hDBFld = hBuf:BUFFER-FIELD(qName). /* Re-init the variable in which we accumulate the field value */ currentFieldValue = "". END. END PROCEDURE. PROCEDURE Characters: DEFINE INPUT PARAMETER charData AS MEMPTR NO-UNDO. DEFINE INPUT PARAMETER numChars AS INTEGER NO-UNDO. /* Get the text value of the field (hDBFld was set to the correct field in StartElement */ currentFieldValue = currentFieldValue + GET-STRING(charData, 1, GET-SIZE(charData)). END PROCEDURE. 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 localName = "Customers" THEN iProcessingState = {&DONE}. ELSE IF localName = "Customer" THEN iProcessingState = {&GETTING-RECORDS}. ELSE IF iProcessingState = {&GETTING-FIELDS} THEN hDBFld:BUFFER-VALUE = currentFieldValue. END PROCEDURE. PROCEDURE EndDocument: /* Show that data made it by displaying temp-table */ FOR EACH ttCustomer: DISPLAY ttCustomer.Name. END. RUN Cleanup. END PROCEDURE. PROCEDURE FatalError: DEFINE INPUT PARAMETER errMessage AS CHARACTER NO-UNDO. /* Not necessary to do anything with PRIVATE-DATA, this is just an example of what you could do */ SELF:PRIVATE-DATA = "FATAL". RUN Cleanup. /* RETURN ERROR in an error handler implicitly calls SELF:STOP-PARSING( ), sets SELF:PARSE-STATUS to SAX-PARSER-ERROR, and raises the ABL ERROR condition. */ RETURN ERROR errMessage + "(Line " + STRING(SELF:LOCATOR-LINE-NUMBER) + ", Col " + STRING(SELF:LOCATOR-COLUMN-NUMBER) + ")". END PROCEDURE. /* This is not a SAX callback; it is just a local utility */ PROCEDURE Cleanup: /* In case we have parsed previous documents */ hBuf:EMPTY-TEMP-TABLE( ). END. |