« McCain Clinton 2008 | Main| My Back Yard - revised »

Closing your XML when errors occur

QuickImage Category Show-n-Tell Thursday

I'm not going to give much of an introduction here, other than to point out that you should write your LotusScript code in such a way that it doesn't blow up. -All right, that wasn't really fair at all. Let me back up, and give you a bit of an explanation about this.

You can create a LotusScript agent in a database on a Domino server that will emit XML to a web browser. I'm sorry, but I'm not going to explain how to do that here. You should know that already. If there is a demand for it, I may post an entry on basic XML generation via LotusScript; but at this point I'm fairly sure it's not needed.

Anyway, on to what this posting is really about: writing your LotusScript agent in such a way that it emits valid XML even when an error occurs.

Here's the scenario: Your LotusScript agent has been called by some remote "thing" (web browser, XMLHttpRequest, etc.), and has started processing. It has already started returning information to the caller via print statements. Everything is going along great, and then it happens: an error occurs. Now, if you've been paying attention; your code is already robust and has error handling built into it. Perhaps you are even logging your error information using something like Julian Robichaux's OpenLog. Good for you. I'm going to give you two functions that you can use in conjunction with your error trapping / handling logic.

NOTE: (I emphasized the word "started" in the previous paragraph because there is actually quite a bit going on "under the covers" I don't want to get sidetracked by that right now -a full discussion of what the Domino Server is actually doing is way beyond the scope of a SNTT posting.)

On to the functions: You can use these to allow your LotusScript agent to finish up properly, even when an error occurs. Meaning, your code deals with the error, but what about the XML? Does your code finish the XML properly, or does it simply stop sending? A half-finished XML stream is worthless to the client / consumer. If an error occurs, you should still close up your XML. In fact, these two functions will also notify the user about the errors. So without further ado, here they are.

Function wrapXMLnode (Byval Content As String, Byval Node As String) As String
%REM This function INTENTIONALLY has no error trapping.
    This function will generate an XML node by wrapping the content
    within the node. If the content is blank, a blank node will be created
    and returned. If the value for node is blank, an empty string ("") will
    be returned. If the value for node contains blank spaces or contains
    the substring "xml", an error will be raised.

    Parameters:
    Content:
    String. The content to wrap within the node.
    Node:
        String. The node to wrap around the content.

    Usage:
        myNode$ = wrapXMLnode(myContent, myNodeName)

    Any raised errors should be handled by the calling code.
%END REM


    Const ERR_XMLNODE_INVALID = 1549
    Const MSG_XMLNODE_INVALID = "The format for the XML node is invalid."

    Dim sumPos As Integer

    wrapXMLnode$ = ""
    Content = Trim$(Content)
    Node = Trim$(Lcase$(Node))
    If (Node$) = "" Then Exit Function
    sumPos = Instr(Node$, " ") + Instr(Node$, "xml")
    If (sumPos > 0) Then Error ERR_XMLNODE_INVALID, MSG_XMLNODE_INVALID & | node="| & Node$ & |".|
    If (Content$ = "" ) Then
        wrapXMLnode$ = "<" & Node$ & " />"
    Else
        wrapXMLnode$ = "<" & Node$ & ">" & Content$ & "& Node$ & ">"
    End If ' (Content$ = "")
End Function ' wrapXMLnode




Function GetErrorXML ( intResult As Integer ) As String
%REM
    This function generates the XML to be returned to the browser.
    It relies on the existence of a globally declared List of Strings
    (lstrErrors), which contains any errors that have occurred.
    Errors within this list are ordered by error number (Err()).
%END REM


    Const NODE_RESULT = |result|
    Const NODE_ERRORLIST = |errorlist|
    Const NODE_ERROR = |error|
    Const NODE_ERRCODE = |errcode|
    Const NODE_ERRTEXT = |errtext|

    Dim strErrXML As String
    Dim strErrCode As String
   
    On Error Goto ErrorTrap

    ' make sure that strErrXML is blank
    strErrXML$ = ""

    ' check for and add the error information first
    If Islist(lstrErrors) Then
        Forall strErr In lstrErrors
            strErrXML$ = strErrXML$ & wrapXMLnode(wrapXMLnode(Cstr(Listtag(strErr)), _
            NODE_ERRCODE) & wrapXMLnode(strErr, NODE_ERRTEXT), NODE_ERROR)
        End Forall ' strErr In lstrErrors
    End If ' Islist(lstrErrors)

    strErrCode = Cstr(intResult)

ExitPoint:
    ' prepend the xml header
    GetErrorXML = wrapXMLnode(strErrCode, NODE_RESULT) & wrapXMLnode(strErrXML$, NODE_ERRORLIST)
    Exit Function

ErrorTrap:
    LogError()
    ' Generate the Error XML
    strErrCode = Cstr(Err())
    strErrXML$ = wrapXMLnode(wrapXMLnode(strErrCode, NODE_ERRCODE) & _
    wrapXMLnode(Error(), NODE_ERRTEXT), NODE_ERROR)
    Resume
ExitPoint
End Function ' GetErrorXML

Hope this helps!

-Devin

Search

Wowsers! A Tag Cloud!

Links

MiscLinks