Release 10.1A: OpenEdge Development:
Messaging and ESB

> ## Publishing, subscribing, and receiving an XML document in a BytesMessage

> The procedures example12.p and example13.p (1 of 2) use a `MEMPTR` variable to publish and receive an XML document in a `BytesMessage` to prevent code-page conversions. The code pages of the document and the 4GL client do not have to match.

> | To run example12.p and example13.p:

> 1. Run example13.p (1 of 2) to subscribe and receive a `BytesMessage` containing an XML document, as shown:

> example13.p
>     /* Receives an XML document in a Bytes message. */
>     DEFINE VARIABLE pubsubsession AS HANDLE.
>     DEFINE VARIABLE msgConsumer1 AS HANDLE.
>     DEFINE VARIABLE stillWaiting AS LOGICAL INIT yes.
>     RUN jms/pubsubsession.p PERSISTENT SET pubsubsession
>                                       ("-H localhost -S 5162 ").
>     RUN setBrokerURL IN pubsubsession ("localhost:2506").
>     RUN beginSession IN pubsubsession.
>     RUN createMessageConsumer IN pubsubsession(THIS-PROCEDURE,
>       "messageHandler",
>       OUTPUT msgConsumer1).
>     RUN subscribe IN pubsubsession (
>                        "xmlTopic",
>                        ?,          /* Not a durable subscription */
>                        ?,          /* No message selector. */
>                        no,         /* noLocal */
>                        msgConsumer1) NO-ERROR.
>     RUN startReceiveMessages IN pubsubsession.
>     RUN waitForMessages IN pubsubsession ("inWait", THIS-PROCEDURE, ?).
>     RUN deleteSession IN pubsubsession.
>     PROCEDURE messageHandler:
>     DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO.
>     DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO.
>     DEFINE OUTPUT PARAMETER replyH AS HANDLE NO-UNDO.
>     DEFINE VAR memptrDoc AS MEMPTR.
>     DEFINE VAR hdoc AS HANDLE.
>     DEFINE VAR hRoot AS HANDLE.
>         memptrDoc = DYNAMIC-FUNCTION('getMemptr':U IN messageH).
>         CREATE X-DOCUMENT hdoc.
>         CREATE X-NODEREF hRoot.
>         hdoc:LOAD("memptr", memptrDoc, FALSE).
>         hdoc:GET-DOCUMENT-ELEMENT(hRoot).
>         RUN GetChildren(hRoot, 1).
>         RUN deleteMessage IN messageH.
>         stillWaiting = false.
>     END.
>     PROCEDURE GetChildren:
>     DEFINE INPUT PARAMETER hParent AS HANDLE.
>     DEFINE INPUT PARAMETER level AS INT.
>     DEFINE VAR i AS INT.
>     DEFINE VAR hNoderef AS HANDLE.
>         CREATE X-NODEREF hNoderef.
>         REPEAT i = 1 TO hParent:NUM-CHILDREN.
>               hParent:GET-CHILD(hNoderef,i).
>               IF hNoderef:NAME = "#text" THEN
>                  MESSAGE "Node text: " hNoderef:NODE-VALUE.
>               ELSE
>                  MESSAGE "Node name: " hNoderef:NAME.
>               RUN GetChildren(hNoderef, (level + 1)).
>         END.
>         DELETE OBJECT hNoderef.
>     END.
>     FUNCTION inWait RETURNS LOGICAL.
>         RETURN stillWaiting.
>     END.

> 2. Run example12.p to publish the `BytesMessage` containing an XML document, as shown:

> example12.p
>     /* Publishes an XML document in a Bytes message. */
>     DEFINE VARIABLE pubsubsession AS HANDLE.
>     DEFINE VARIABLE mesgH AS HANDLE.
>     DEFINE VARIABLE memVal AS MEMPTR.
>     DEFINE VAR hdoc AS HANDLE.
>     RUN jms/pubsubsession.p PERSISTENT SET pubsubsession
>                                       ("-H localhost -S 5162 ").
>     RUN setBrokerURL IN pubsubsession ("localhost:2506").
>     RUN beginSession IN pubsubsession.
>     RUN createBytesMessage IN pubsubsession (OUTPUT mesgH).
>     CREATE X-DOCUMENT hdoc.
>     hdoc:LOAD("file", "personal.xml", FALSE).
>     hdoc:SAVE("memptr", memVal).
>     RUN setMemptr IN mesgH(memVal, ?, ?).
>     RUN publish IN pubsubsession ("xmlTopic", mesgH, ?, ?, ?).
>     SET-SIZE(memVal) = 0.
>     RUN deleteMessage IN mesgH.
>     RUN deleteSession IN pubsubsession.
>     /*
>      The personal.xml document:
>     <?xml version="1.0" encoding='UTF-8' ?>
>     <personnel>
>       <person id="Irving.Nigrini">
>         <name><family>Nigrini</family> <given>Irving</given></name>
>         <email>inigrini@subpargolf.com</email>
>         <link manager="Thomas.Roy"/>
>       </person>
>       <person id="Jules.Nigrini">
>         <name><family>Nigrini</family> <given>Jules</given></name>
>         <email>jnigrini@subpargolf.com</email>
>         <link manager="Thomas.Roy"/>
>       </person>
>     </personnel>
>     */

> ##### XML code page encoding

> 4GL applications work with the built-in XML parser. It is important to consider the code page encoding of XML messages. In principle, XML documents can be encoded with any code page. However, XML parsers support some or all code pages, and XML parsers also differ with respect to the code page conversions that they support.

> 4GL clients set and get XML text using the 4GL `CHARACTER` data type. `CHARACTER` data is encoded by the 4GL interpreter according to the internal code page (the `-cpinternal` startup parameter). The 4GL-JMS implementation automatically converts the text to Unicode when it is sent to the JMS server, and from Unicode to the internal client’s code page when the text is sent from the server to the client.

> In general, when the characters used by the XML document are from the 7-byte ASCII subset, there are no issues the 4GL programmer has to consider. Otherwise, observe the following examples and guidelines in the following examples.

> ##### Code page example 1

> In this example, two 4GL clients use the ISO8859-1 code page:

> - Client1 sets XML text in an `XMLMessage` and sends it.

> - Client2 receives the message, extracts the text, stores it in a `MEMPTR` variable, and creates an XML document. (See the "Publishing, subscribing, and receiving an XML document in a BytesMessage" section.)

> The following code-page conversions take place:

> 1. ISO8859-1 (client1) to Unicode (SonicMQ `XMLMessage`).

> 2. Unicode (SonicMQ `XMLMessage`) to ISO8859-1 (client2).

> In this example, the XML parser parses the XML document correctly if:

> 1. The header of the document specifies that the encoding is ISO8859-1.

> 2. The parser can handle ISO8859-1.

> ##### Code page example 2

> In this example, two 4GL clients use ISO8859–1 for their internal code page. Client1 saves a UTF–8 encoded XML document in a `MEMPTR` variable (calling the `X–DOC:SAVE()` 4GL method) and then uses the 4GL `GET–STRING` statement to extract the text from the `MEMPTR` and pass it into the `XMLMessage`. (This is a deliberate error.) UTF–8 (Unicode Transformation Format) is an 8-bit encoding form that serializes a Unicode scalar value as a sequence of one to four bytes.

> A 4GL client cannot mix code pages. The text it sets in the `XMLMessage` must be encoded in the same code page as the client’s internal code page. In general, a `MEMPTR` variable must be used carefully, since it can have any data in it. The 4GL programmer must be sure that it contains only `NULL` free text (no embedded `NULL` bytes), encoded with the same code page as the internal code page, before loading it into an `XMLMessage`.

> In this example, if the 4GL client cannot be started up with `–cpinternal` UTF–8, but still wants to use 4GL-JMS to pass that UTF–8 document, it can use a `BytesMessage` or bytes elements in a `StreamMessage`. When sent as bytes, the XML data will get to the receiver uninterpreted and unconverted. The 4GL receiver can then set the data in a `MEMPTR` variable and load the parser.

> A second option is to convert the text (and the document’s header) to ISO8859–1 using the `CODEPAGE–CONVERT` 4GL function. However, if `-cpinternal` represents all character, the conversion is automatic if you use `LONGCHAR` or `CHAR`. If `-cpinternal` represents all characters, the conversion is also automatic when you use the new built-in XML routines (`SAX-WRITER` or `setX-Document`). When you use the new built-in XML routines, you can create, send, and receive UTF-8 XML documents.

> If the 4GL receiver of an `XMLMessage` is unsure about the XML header encoding declaration, it must check it and perhaps modify it to match its internal code page before loading the parser.

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095