Creating HTTP Requests using Microsoft's XML Parser

Patrick Ransom, 19 August 2001

Category: Agents; Keywords: XML parse HTTP

Thought I would write a quick one about something useful I've been wanting to do for sometime now and finally figured out. It is yet another one of those things that can be quite helpful when applied correctly to solve a problem. Our problem seemed simple enough, as the hard ones often do! We were building an e-commerce solution for a client of ours and got to the portion of the application where we had built the shopping cart, but needed to figure out the shipping rate for the entire order. Our client wanted to use the United States Postal Service's (USPS) API for calculating shipping rate. As we began to read the USPS API we quickly realized that the generated request had to be in XML. Personally, you can fit all of my XML knowledge into a very small container - that's how much XML experience I've had. I do however know a fair amount about HTML and creating HTTP POST requests. As we

read through the USPS API, which is about 92 pages (ouch), we discovered basically all we needed to do was build the HTTP Post request, send it, wait for the response, and parse it. Try searching on Notes.net for XML parser and lotusscript and you get a ton of articles mentioning how "nice it would be" to have such functionality. Luckily we found an article by Paul Ray that we modified to solve our problem.

Prerequisites:

This script must be running on the Win32 platform to work, so if you're still reading this - you're in luck. This example describes creating a new HTTP Post request using calls to the MSXML parser that is installed with Internet Explorer 5. We are running Lotus Domino 5.08 on a Windows 2000 Advanced Server platform with Internet Explorer 5 installed and the script worked like a charm.


The Basics:

In our situation, we needed to calculate the shipping rate before we opened the document in "checkout" mode. The Lotusscript agent is called in the WebQueryOpen event to give us the ability to modify field values before the document is opened. Here is the basic structure of the agent:

  1. Get a handle on the current web document through the session.documentContext
  2. Strip off some values that were appended to the ?OpenAgent URL
  3. Initialize the MSXML Object
  4. Build the HTTP POST Request in Lotusscript string format
  5. Send the HTTP POST Request
  6. Receive the response
  7. Parse out the XML Tag value
  8. Add that parsed value to a field on the current web document
  9. Save the current web document
  10. Null out the MSXML Object
  11. Open the web document

The Parsing:

The parsing of the XML response is simplified using the above method because the response is now basically just a very large text string. All of you Lotusscript gurus no doubt have tons of scripts to manipulate string data. We used two very basic functions that allowed us to grab the value that was between the <Postage> opening XML tag and the </Postage> closing XML tag. There are several ways to manipulate the text once you've received the response - your method for text parsing is as good as any one elses.

Where improvements can be made:

Obviously not every solution is fool proof unless you develop a solution with superb error checking. In our example, very little error checking is used. Once you receive the MSXML response, you could opt to use the objHTTP.status to test the response code (e.g., 200, 401, etc.).

The Code:

Our Lotusscript agent was created so as to be run from the WebQueryOpen event on one of our forms. The agent itself was set to Run Manually from the Agent List and Run Once(@Commands may be used). See Figure 1 below.

image
Figure 1: The agent property.


Sub Initialize
%REM
This routine will create a new HTTP POST request, send values, and retrieve the response from the server. This is done via the XMLHTTP object of the MSXML parser.
%END REM

Dim s As New NotesSession
Dim doc As NotesDocument
Dim objHttp As Variant
Dim response As String
Dim request As String
Dim beginTag As String
Dim endTag As String
Dim rightHalf As String
Dim leftHalf As String


On Error Goto ErrHandler

Set db = s.CurrentDatabase
Set doc = s.DocumentContext

query_string = doc.getitemvalue("Query_String")(0)

If Instr(query_string, "&ZC=") Then

destZipCode = Strright(query_string,"&ZC=")

' --- instantiate an MSXML XMLHTTP object
set objHttp = CreateObject("Microsoft.XMLHTTP")

' --- open a new POST request and set the Content-type header

url = |Http://production.shippingapis.com/ShippingAPI.dll|
req = |API=Rate&XML=<RateRequest USERID="5555555555"
PASSWORD="777777777777"><Package ID="TestID">
<Service>Priority</Service><ZipOrigination>55555
</ZipOrigination><ZipDestination>|+destZipCode+|
</ZipDestination><Pounds>5</Pounds><Ounces>10
</Ounces><Container>None</Container><Size>REGULAR
</Size><Machinable></Machinable></Package>
</RateRequest>|

objHttp.open "POST", url, False, "", ""
objHttp.setRequestHeader "Content-type", "application/x-www-form-urlencoded"

objHttp.send(req)

response = objHttp.responseText

beginTag = "<Postage>"
endTag = "</Postage>"

rightHalf = RightBack(response,beginTag)
LeftHalf = myLeft(rightHalf,endTag)

doc.Shipping = Ccur(LeftHalf)
Call doc.Save(True, True)


Cleanup:

Set objHttp=Nothing

newHREF = "/" + db.FilePath + "/0/" + doc.UniversalID + "?OpenDocument"
Print |[| + newHREF + |]|

End If
Exit Sub

ErrHandler:

' --- runtime error occurred
Msgbox Error$, 48, "Runtime Error"
Resume Cleanup

End Sub

The following two functions are those referenced in the above routine and used to extract the required string from within the XML.

Function RightBack ( sourceString As String, searchString As String ) As String

For i% = Len(sourceString) To 1 Step -1
sourceStringBack$=sourceStringBack$ & Mid(sourceString, i%, 1)
Next

For i% = Len(searchString) To 1 Step -1
searchStringBack$=searchStringBack$ & Mid(searchString, i%, 1)
Next

pos% = Instr ( sourceStringBack$, searchStringBack$ )

If pos% > 0 Then pos% = pos% -1
result$ = Left ( sourceStringBack$, pos% )

For i% = Len(result$) To 1 Step -1
turn$=turn$ & Mid(result$, i%, 1)
Next

RightBack=turn$
End Function

Function myLeft ( sourceString As String, searchString As String ) As String

pos% = Instr ( sourceString, searchString )
If pos% > 0 Then pos% = pos% -1

myLeft = Left ( sourceString, pos% )
End Function


In Summary:

Hopefully the method I have described above demonstrates how you too can use the MSXML object and tailor it to your own needs. To do this all you need do is edit the code modifying the URL and the req values and you're off and running! Let your imagination run wild as the possible solutions you can build are endless. You can even use this method to automatically fill out Notes Forms over the web without any user interaction.


About the Author:


With over seven years experience as a Lotus Notes professional, Patrick has worked on some of the largest and most complex groupware implementations. Specializing in infrastructure design, messaging, and application development, Patrick has a broad range of experience designing, developing, deploying, and supporting departmental and enterprise messaging and groupware solutions. A CLP Principal Application Developer and CLP Principal Systems Administrator, Patrick has developed and implemented large scale messaging solutions, business to business (b2b) architecture and development solutions, and production migrations and rollouts. Patrick has coordinated with and traveled to numerous organizations to provide on site business process analysis, groupware consulting, application development, and messaging implementations. Patrick is the CEO and Senior Software Engineer at Ixion, L.L.C. (http://www.ixiononline.com) As an established Lotus Domino developer, Patrick has contributed development articles to and is published in the Domino Update periodical.