Using Complex Data Types with XML Web Services in Microsoft Access 2002
This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.
Frank C. Rice
Microsoft Corporation
July 2002
Applies to:
Microsoft® Access 2002
Microsoft Office Web Services Toolkit 2.0
Summary: Learn how XML Web services are an efficient way to expose the functionality of business and enterprise applications as a service, either over an intranet or the Internet. The Web Service References Tool 2.0 can make using XML Web services from a client application very simple. (40 printed pages)
Download setup.exe.
Contents
Introduction
The ComplexTypesDemo.mdb Access 2002 Database
The frmSimpleTypes Form
Combining Simple Data Types
The SalesRankNPrice XML Web Service
The All User-Defined Complex Data Type
The frmSalesRankNPrice Form
The frmZipCodeResolver Form
The frmCurrentWeather Form
Conclusion
Introduction
In this article, we will demonstrate using a sample Microsoft® Access 2002 database as a client application to access a number of XML Web services using both simple and complex data types. The database uses the Web Service References Tool 2.0, which is provided with the Microsoft Office XP Web Services Toolkit 2.0.
For more information on XML Web services and the Office XP Web Services Toolkit 2.0, see the article Using the Office XP Web Services Toolkit 2.0 to Interact with Complex Types in XML Web Services.
The ComplexTypesDemo.mdb Access 2002 Database
The ComplexTypesDemo.mdb is an Access 2002 database containing four forms, which are used to access and display the results of several XML Web services. The forms and the XML Web services they access are:
frmSimpleTypes
This form demonstrates accessing XML Web services which use simple data types. This form uses the following XML Web services:
- The WeatherRetriever XML Web service provides the
GetTemperature
method which accepts a Zip Code as a String value and returns the current temperature as a Single value. - The TempConverter XML Web service provides the
CtoF
method which accepts a temperature in Fahrenheit as a Long value and returns the temperature in centigrade, also as a Long value, and theFtoC
method which performs the inverse of theCtoF
method. - The PigLatin XML Web service provides the
toPigLatin
method which accepts an English phrase as a String value and returns the phrase in pig Latin, also as a String value. - The Romulan XML Web service provides the
RomanToInt
method which accepts an Integer value and returns the Roman numeral equivalent as a String value, and theIntToRoman
method which performs the inverse of theRomanToInt
method. - The NumToWords XML Web service provides the
NumToWords
method which accepts a number as a Double value and returns a String value representing the number in words. - The Clock XML Web service provides the following:
- The
GetDayOfYear
method, which accepts a date as a String value and returns a value representing the current day of the year as a Double value. - The
GetDaysToEndYear
method, which accepts a date as a String value and returns a value representing the number of days remaining in the current year as a Double value. - The
GetUTC_Time
method, which returns the Universal Coordinated Time (UTC) for the current date as a Date value. - The
GetLocalTime
method, which returns the local date and time for the current date as a Date value. - The
GetDayOfCurrentYear
method, which returns the number of the day of the year for the current date as a Double value. - The
GetDaysToNextYear
method, which returns the number of days remaining in this year for the current date as a Double value.
- The
frmCurrentWeather
This form accesses the WeatherRetriever XML Web service, which provides theGetWeather
method. This method accepts a Zip Code as a String value and returns:
- A complex data type structure (
struct_CurrentWeather
) consisting of four String values representing the date and time the weather data was last updated. - The URL to an icon representing the current weather conditions.
- The current weather conditions.
- The direction of the barometer reading.
- Three Single values representing the current temperature, the current humidity, and the barometer reading.
frmSalesRankNPrice
This form accesses the SalesRankNPrice XML Web service which provides a number of methods including theGetAll
method. This method accepts an International Standard Book Number (ISBN) and returns a complex data type structure (struct_All
) consisting of four String values representing the Amazon sales ranking, the Amazon price, the Barnes & Noble sales ranking, and the Barnes & Noble price.
frmZipCodeResolver
This form accesses the ZipCodeResolver XML Web service, which provides theCorrectedAddressXml
method. This method accepts four String values representing an access code, a street address, city, and state, and returns a complex data type structure consisting of five String values representing a correct United States Postal Service (USPS) street address, city, state, short Zip Code, and full Zip Code (ZIP + 4).
The frmSimpleTypes Form
ThefrmSimpleTypes
form demonstrates using the Web Service References Tool to access XML Web services using simple data types. The form consists of text boxes for input and output, and buttons for invoking the XML Web service (see Figure 1).
Figure 1. The frmSimpleTypes form
To use this XML Web service, the user types either a value in inches or a value in millimeters, and then clicks a button, which returns an equivalent value in inches or millimeters, depending on the type of input. For example, in Figure 1, I entered 144 in the inches box and the XML Web service returned 3657.6 millimeters.
When you set a reference to the WSDL file for this XML Web service, the Web Service References Tool creates theclsws_ConvertService
class, which contains the following code. The first section provides comments about how this code was created, followed by instructions on how to declare and instantiate this class:
'*****************************************************************
'This class was created by the Web Service References Tool 2.0.
'
'Created: 4/30/2002 09:06:06 AM
'
'Description:
'This class is a Visual Basic for Applications class representation of
the Web service
'as defined by http://www.xmlbus.com:9010/xmlbus/container/
Converter/ConverterService/ConverterPort?WSDL.
'
'To Use:
'Dimension a variable as new clsws_ConverterService, and then write
code to
'use the methods provided by the class.
'Example:
' Dim ExampleVar as New clsws_ConverterService
' debug.print ExampleVar.wsm_inchToMM("Sample Input")
'
'For more information, see Complex Types in Web Service References
'Tool 2.0 Help.
'
'Changes to the code in this class may result in incorrect behavior.
'
'*****************************************************************
Next, two internal class variables are dimensioned, representing the SoapClient30 object and the URL to the XML Web service's WSDL file, respectively. The SoapClient30 proxy object always starts with the prefix sc_ followed by the XML Web service name. The constantc_WSDL_URL
will always have the same name regardless of the class file.
...
' Dimensioning private class variables.
Private sc_ConverterService As SoapClient30
Private Const c_WSDL_URL As String =
"http://www.xmlbus.com:9010/xmlbus/container/
Converter/ConverterService/ConverterPort?WSDL"
...
Then, other class variables are declared, representing a String value containing the name of the service, the port that receives the SOAP requests, and the XML Web service namespace, respectively.
...
Private Const c_SERVICE As String = "ConverterService"
Private Const c_PORT As String = "ConverterPort"
Private Const c_SERVICE_NAMESPACE As String = "urn:target-converter-
service"
...
Next, the Class_Initialize event first declares an empty String as str_MSML
. As we will see later in this article, if the XML Web service being referenced uses a complex data type, thestr_WSML
variable would contain a concatenated String value representing a mapping between the complex data type structure class created by the Web Service References Tool and the complex data type structure defined in the WSDL file.
Note A Web Services Meta Language (WSML) file maps the methods of the XML Web service (as described in the WSDL file) to specific methods in the Component Object Model (COM) object which implements the XML Web service. The WSML file is only necessary for the implementation of the Microsoft SOAP dynamic-link library (DLL).
The procedure then uses the MSSoapInit2 method of the SoapClient30 proxy object to instantiate thesc_ConverterService
object. Next, various properties are set related to using Microsoft Internet Explorer with the proxy server:
Private Sub Class_Initialize()
'*****************************************************************
'This subroutine will be called each time the class is
instantiated.
'Creates sc_ComplexTypes as new SoapClient30, and then
'initializes sc_ComplexTypes.mssoapinit2 with WSDL file found in
'http://www.xmlbus.com:9010/xmlbus/container/
Converter/ConverterService/ConverterPort?WSDL.
'*****************************************************************
Dim str_WSML As String
str_WSML = ""
Set sc_ConverterService = New SoapClient30
sc_ConverterService.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE, c
_PORT, c_SERVICE_NAMESPACE
'Use the proxy server defined in Internet Explorer's LAN settings
by
'setting ProxyServer to <CURRENT_USER>
sc_ConverterService.ConnectorProperty("ProxyServer") =
"<CURRENT_USER>"
'Autodetect proxy settings if Internet Explorer is set to
autodetect
'by setting EnableAutoProxy to True
sc_ConverterService.ConnectorProperty("EnableAutoProxy") = True
End Sub
The Class_Terminate event is used to clean up resources that are no longer needed, namely, the SoapClient30 proxy object.
Private Sub Class_Terminate()
'*****************************************************************
'This subroutine will be called each time the class is destructed.
'Sets sc_ComplexTypes to Nothing.
'*****************************************************************
'Error Trap
On Error GoTo Class_TerminateTrap
Set sc_ConverterService = Nothing
Exit Sub
Class_TerminateTrap:
ConverterServiceErrorHandler ("Class_Terminate")
End Sub
TheConverterServiceErrorHandler
subroutine is used to handle any errors raised by the Web server hosting the XML Web service. This subroutine's name is always prefixed by the XML Web service name followed by the text ErrorHandler.
Private Sub ConverterServiceErrorHandler(str_Function As String)
'*****************************************************************
'This subroutine is the class error handler. It can be called from
any class subroutine or function
'when that subroutine or function encounters an error. Then, it
will raise the error along with the
'name of the calling subroutine or function.
'*****************************************************************
'SOAP Error
If sc_ConverterService.faultcode <> "" Then
Err.Raise vbObjectError, str_Function,
sc_ConverterService.faultstring
'Non SOAP Error
Else
Err.Raise Err.Number, str_Function, Err.Description
End If
End Sub
Finally, proxy methods corresponding to the XML Web service's two methods are generated.
Public Function wsm_inchToMM(ByVal sng_param0 As Single) As Single
'*****************************************************************
'Proxy function created from
http://www.xmlbus.com:9010/xmlbus/container/
Converter/ConverterService/ConverterPort?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_inchToMMTrap
wsm_inchToMM = sc_ConverterService.inchToMM(sng_param0)
Exit Function
wsm_inchToMMTrap:
ConverterServiceErrorHandler "wsm_inchToMM"
End Function
Public Function wsm_mmToInch(ByVal sng_param0 As Single) As Single
'*****************************************************************
'Proxy function created from
http://www.xmlbus.com:9010/xmlbus/container/
Converter/ConverterService/ConverterPort?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_mmToInchTrap
wsm_mmToInch = sc_ConverterService.mmToInch(sng_param0)
Exit Function
wsm_mmToInchTrap:
ConverterServiceErrorHandler "wsm_mmToInch"
End Function
Thewsm_inchToMM
method is the proxy class for theinchToMM
method of the XML Web service as representing by thesc_ConverterService
object. Thewsm_inchToMM
method accepts a Single value representing a measure in inches and returns a Single value representing the equivalent measure in millimeters. Thewsm_mmToInch
works as the inverse of thewsm_inchToMM
method, returning a value in inches for a measure in millimeters.
The following code is executed when the user clicks thecmdLength
command button.
Private Sub cmdLength_Click()
Dim clsLength As New clsws_ConverterService
Dim sglInch As Single
Dim sglMM As Single
On Error GoTo cmdLength_Click_Err
DoCmd.Hourglass True
Me![txtInch].SetFocus
If Me![txtInch].Value <> "" Or Not IsNull(Me![txtInch].Value) Then
sglInch = Trim(Me![txtInch].Value)
sglMM = clsLength.wsm_inchToMM(sglInch)
Me![txtMM].Value = sglMM
ElseIf Me![txtMM].Value <> "" Or Not IsNull(Me![txtMM].Value) Then
sglMM = Trim(Me![txtMM].Value)
sglInch = clsLength.wsm_mmToInch(sglMM)
Me![txtInch].Value = sglInch
Else
MsgBox "Please enter an inch or millimeter and click the
button."
GoTo cmdLength_Click_End
End If
cmdLength_Click_End:
DoCmd.Hourglass False
Exit Sub
cmdLength_Click_Err:
MsgBox "The service is busy. Please try again later."
GoTo cmdLength_Click_End
End Sub
First, we declare an object as clsws_ConverterService
, which represents the SoapClient30 object used to provide access to the XML Web service methods. Then, after setting two String variables to hold the value entered by the user representing either inches or millimeters, we check to see whether the user typed a value in the inches box or the millimeters box. If inches were entered, we set thesglInch
variable to the value in the text box, and call thewsm_inchToMM
proxy method and assign the results to the millimeter box for display. If the user entered a value in the millimeter box instead, we set thesglMM
variable to the value in the box, call the wsm_mmToInch
proxy method, and display the results in the inches box. If the user didn't type a value in either box before clicking the button, we display a message and exit the procedure. You can see the results from this XML Web service in Figure 1.
Combining Simple Data Types
Now let's look at an example where we combine the simple data types returned from an XML Web service to present multiple, related data to the user. For this example, we will look at the Clock XML Web service, which provides a number of methods that send and receive simple data types.
This XML Web service provides theGetUTC_Time
method which returns the Universal Coordinated Time (UTC) for the current date as a Date value, theGetLocalTime
method which returns the local date and time for the current date as a Date value, theGetDayOfCurrentYear
method which returns the number of the day of the year for the current date as a Double value, and theGetDaysToNextYear
method which returns the number of days remaining in this year for the current date as a Double value. By combining the return results from these simple data types together into a single message, we can provide related data to the user and simulate a complex data type.
Looking at the code generated by the Web Service References Tool:
'Dimensioning private class variables.
Private sc_clock As SoapClient30
Private Const c_WSDL_URL As String = "http://www.xml-
webservices.net/services/time_server/clock.asmx?WSDL"
Private Const c_SERVICE As String = "clock"
Private Const c_PORT As String = "clockSoap"
Private Const c_SERVICE_NAMESPACE As String = "http://www.xml-
webservices.net/services/time_server"
Private Sub Class_Initialize()
'*****************************************************************
'This subroutine will be called each time the class is
instantiated.
'Creates sc_ComplexTypes as new SoapClient30, and then
'initializes sc_ComplexTypes.mssoapinit2 with WSDL file found in
'http://www.xml-webservices.net/services/
time_server/clock.asmx?WSDL.
'*****************************************************************
Dim str_WSML As String
str_WSML = ""
Set sc_clock = New SoapClient30
sc_clock.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE, c_PORT,
c_SERVICE_NAMESPACE
'Use the proxy server defined in Internet Explorer's LAN settings
by
'setting ProxyServer to <CURRENT_USER>
sc_clock.ConnectorProperty("ProxyServer") = "<CURRENT_USER>"
'Autodetect proxy settings if Internet Explorer is set to
autodetect
'by setting EnableAutoProxy to True
sc_clock.ConnectorProperty("EnableAutoProxy") = True
End Sub
Private Sub Class_Terminate()
'*****************************************************************
'This subroutine will be called each time the class is destructed.
'Sets sc_ComplexTypes to Nothing.
'*****************************************************************
'Error Trap
On Error GoTo Class_TerminateTrap
Set sc_clock = Nothing
Exit Sub
Class_TerminateTrap:
clockErrorHandler ("Class_Terminate")
End Sub
Private Sub clockErrorHandler(str_Function As String)
'*****************************************************************
'This subroutine is the class error handler. It can be called from
any class subroutine or function
'when that subroutine or function encounters an error. Then, it
will raise the error along with the
'name of the calling subroutine or function.
'*****************************************************************
'SOAP Error
If sc_clock.faultcode <> "" Then
Err.Raise vbObjectError, str_Function, sc_clock.faultstring
'Non SOAP Error
Else
Err.Raise Err.Number, str_Function, Err.Description
End If
End Sub
The first sections of code are similar to those discussed in the previous example. After declaring variables representing attributes of the XML Web service such as service name, the URL to the WSDL file, and so forth, the Web Service References Tool generates subroutines to create or terminate the SoapClient30 object, and to provide error handling. Next, functions containing the proxy methods of the Clock XML Web service are generated:
Public Function wsm_GetUTC_Time() As Date
'*****************************************************************
'Proxy function created from http://www.xml-
webservices.net/services/time_server/clock.asmx?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_GetUTC_TimeTrap
wsm_GetUTC_Time = sc_clock.GetUTC_Time()
Exit Function
wsm_GetUTC_TimeTrap:
clockErrorHandler "wsm_GetUTC_Time"
End Function
Public Function wsm_GetLocalTime() As Date
'*****************************************************************
'Proxy function created from http://www.xml-
webservices.net/services/time_server/clock.asmx?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_GetLocalTimeTrap
wsm_GetLocalTime = sc_clock.GetLocalTime()
Exit Function
wsm_GetLocalTimeTrap:
clockErrorHandler "wsm_GetLocalTime"
End Function
Public Function wsm_GetDayOfCurrentYear() As Double
'*****************************************************************
'Proxy function created from http://www.xml-
webservices.net/services/time_server/clock.asmx?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_GetDayOfCurrentYearTrap
wsm_GetDayOfCurrentYear = sc_clock.GetDayOfCurrentYear()
Exit Function
wsm_GetDayOfCurrentYearTrap:
clockErrorHandler "wsm_GetDayOfCurrentYear"
End Function
Public Function wsm_GetDaysToNextYear() As Double
'*****************************************************************
'Proxy function created from http://www.xml-
webservices.net/services/time_server/clock.asmx?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_GetDaysToNextYearTrap
wsm_GetDaysToNextYear = sc_clock.GetDaysToNextYear()
Exit Function
wsm_GetDaysToNextYearTrap:
clockErrorHandler "wsm_GetDaysToNextYear"
End Function
As can be seen, each of these procedures are essentially identical in that they accept no input arguments (the current date is used by the XML Web service) and return a single data type. The first procedurewsm_GetUTC_Time
gets the Coordinated Universal Time (UTC) of the current date.
The next procedures get the local date and time, the current day of the year, and the number of days left until the end of the year, respectively.
The following code is used to call each of these procedures and display the results in a message dialog box:
Private Sub cmdGetDateInfo_Click()
Dim clsDateInfo As New clsws_clock
Dim datUTC As Date
Dim timLocal As Date
Dim dblDayofYear As Double
Dim dblDaysLeft As Double
On Error GoTo cmdGetDateInfo_Click_Err
DoCmd.Hourglass True
datUTC = clsDateInfo.wsm_GetUTC_Time
timLocal = clsDateInfo.wsm_GetLocalTime
dblDayofYear = clsDateInfo.wsm_GetDayOfCurrentYear
dblDaysLeft = clsDateInfo.wsm_GetDaysToNextYear
MsgBox "The Coordinated Universal Time is " & datUTC & vbCrLf & _
"The date and local time is " & timLocal & vbCrLf & _
"Today is the " & dblDayofYear & " day of this year" & vbCrLf &
_
"There are " & dblDaysLeft & " days left in this year.",
vbOKOnly, "Date Information"
cmdGetDateInfo_Click_End:
DoCmd.Hourglass False
Exit Sub
cmdGetDateInfo_Click_Err:
MsgBox "The service is busy. Please try again later."
GoTo cmdGetDateInfo_Click_End
End Sub
First, we declare an object asclsws_clock
that represents the SoapClient30 object. Then, we declare variables to hold the results of the method calls to the XML Web service. Next, we call each of the proxy methods and assign the results. And finally, we display a message dialog box and exit the procedure. You can see the results from this XML Web service in Figure 2.
Figure 2. Message displaying the results of the Clock XML Web service
ThefrmSimpleTypes
form contains a number of additional classes generated by the Web Service References Tool as well as procedures that call other XML Web services using simple data types. Exploration of these class modules and associated subroutines is left to the reader.
Now we will look at XML Web services that use complex data types.
The SalesRankNPrice XML Web Service
ThefrmSalesRankNPrice
form demonstrates accessing an XML Web service that uses complex data types by using the SalesRankNPrice XML Web service, which contains methods that support both simple and complex data types. The methods utilizing simple data types accept a String value and return a String value, as follows:
GetAmazonPrice
(accepts a String value representing an ISBN; returns a String value representing the Amazon sales price).GetAmazonSalesRank
(accepts a String value representing an ISBN; returns a String value representing the Amazon sales rank).GetAmazonUKPrice
(accepts a String value representing an ISBN; returns a String value representing the Amazon UK sales price).GetAmazonUKSalesRank
(accepts a String value representing an ISBN; returns a String value representing the Amazon UK sales rank).GetBNPrice
(accepts a String value representing an ISBN; returns a String value representing the Barnes & Noble sales price).GetBNSalesRank
(accepts a String value representing an ISBN; returns a String value representing the Barnes & Noble sales rank).
In addition, the SalesRankNPrice XML Web service also supports complex data types:
GetAll
(accepts a String value representing an ISBN; returns four String values representing the Amazon sales rank, the Amazon price, the Barnes & Noble sales rank, and the Barnes & Noble price).GetAmazonAndBNPrice
(accepts a String value representing an ISBN; returns two String values representing the Amazon price and the Barnes & Noble price).GetAmazonAndBNSalesRank
(accepts a String value representing an ISBN; returns two String values representing the Amazon sales rank and the Barnes & Noble sales rank).GetAmazonSalesRankNPrice
(accepts a String value representing an ISBN; returns two String values representing the Amazon sales rank and sales price).GetBNSalesRankNPrice
(accepts a String value representing an ISBN; returns two String values representing the Barnes & Noble sales rank and sales price).
To illustrate using complex data types with XML Web services, we will use the GetAll
method in thefrmSalesRankNPrice
form. This method accepts an ISBN as a String value and returns thestruct_All
structure containing four String values.
Looking at the code generated by the Web Service References Tool, first, we declare variables representing the SoapClient30 object and the URL to the XML Web service's WSDL file, respectively.
...
'Dimensioning private class variables.
Private sc_SalesRankNPrice As SoapClient30
Private Const c_WSDL_URL As String =
"http://www.perfectxml.net/WebServices/
SalesRankNPrice/BookService.asmx?wsdl"
...
Then, other variables are declared, representing the name of the service, the port that receives the SOAP requests, and the XML Web service namespace, respectively.
...
Private Const c_SERVICE As String = "SalesRankNPrice"
Private Const c_PORT As String = "SalesRankNPriceSoap"
Private Const c_SERVICE_NAMESPACE As String =
"http://www.PerfectXML.com/NETWebSvcs/BookService"
WSML = c_WSML & " </servicemapping>"
...
The Class_Initialize event procedure first declares a concatenated String variable that maps the XML Web service'sAll
complex data type (used with theGetAll
method) to the proxy structure defined in the file struct_All
, as str_WSML
.
Private Sub Class_Initialize()
'*****************************************************************
'This subroutine will be called each time the class is
instantiated.
'Creates sc_ComplexTypes as new SoapClient30, and then
'initializes sc_ComplexTypes.mssoapinit2 with WSDL file found in
'http://www.perfectxml.net/WebServices/
SalesRankNPrice/BookService.asmx?wsdl.
'*****************************************************************
Dim str_WSML As String
str_WSML = "<servicemapping name='SalesRankNPrice'>"
str_WSML = str_WSML & "<service name='SalesRankNPrice'>"
str_WSML = str_WSML & "<using
PROGID='MSSOAP.GenericCustomTypeMapper30' cachable='0'
ID='GCTM'/>"
str_WSML = str_WSML & "<types>"
str_WSML = str_WSML & "<type name='All'
targetNamespace='http://www.PerfectXML.com/
NETWebSvcs/BookService' uses='GCTM'
targetClassName='struct_All'/>"
str_WSML = str_WSML & "<type name='Prices'
targetNamespace='http://www.PerfectXML.com/
NETWebSvcs/BookService' uses='GCTM'
targetClassName='struct_Prices'/>"
str_WSML = str_WSML & "<type name='SalesRankNPrice1'
targetNamespace='http://www.PerfectXML.com/
NETWebSvcs/BookService' uses='GCTM'
targetClassName='struct_SalesRankNPrice1'/>"
str_WSML = str_WSML & "<type name='SalesRanks'
targetNamespace='http://www.PerfectXML.com/
NETWebSvcs/BookService' uses='GCTM'
targetClassName='struct_SalesRanks'/>"
str_WSML = str_WSML & "</types>"
str_WSML = str_WSML & "</service>"
str_WSML = str_WSML & "</servicemapping>"
Set sc_SalesRankNPrice = New SoapClient30
sc_SalesRankNPrice.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE,
c_PORT, c_SERVICE_NAMESPACE
'Use the proxy server defined in Internet Explorer's LAN settings
by
'setting ProxyServer to <CURRENT_USER>
sc_SalesRankNPrice.ConnectorProperty("ProxyServer") =
"<CURRENT_USER>"
'Autodetect proxy settings if Internet Explorer is set to
autodetect
'by setting EnableAutoProxy to True
sc_SalesRankNPrice.ConnectorProperty("EnableAutoProxy") = True
Set sc_SalesRankNPrice.ClientProperty("GCTMObjectFactory") = New
clsof_Factory_SalesRankNPri
End Sub
TheAll
complex data type is defined in the SalesRankNPrice XML Web service WSDL file with the following code:
...
<s:element name="GetAll">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="ISBN"
type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetAllResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetAllResult"
type="s0:All" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="All">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="AmazonSalesRank"
type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="AmazonPrice"
type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="BNSalesRank"
type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="BNPrice"
type="s:string" />
</s:sequence>
</s:complexType>
...
The Class_Initialize event procedure then uses the MSSoapInit2 method of the SoapClient30 proxy object to instantiate thesc_SalesRankNPrice
object. TheClientProperty
method of the SoapClient30 object is then used to create a new instance of theclsof_Factory_SalesRankNPri
class.
The Class_Terminate event is used to clean up resources that are no longer needed.
Private Sub Class_Terminate()
'*****************************************************************
'This subroutine will be called each time the class is destructed.
'Sets sc_ComplexTypes to Nothing.
'*****************************************************************
'Error Trap
On Error GoTo Class_TerminateTrap
Set sc_SalesRankNPrice = Nothing
Exit Sub
Class_TerminateTrap:
SalesRankNPriceErrorHandler ("Class_Terminate")
End Sub
TheSalesRankNPriceErrorHandler
subroutine is used to handle any errors raised by the Web server hosting the XML Web service.
Private Sub SalesRankNPriceErrorHandler(str_Function As String)
'*****************************************************************
'This subroutine is the class error handler. It can be called from
any class subroutine or function
'when that subroutine or function encounters an error. Then, it
will raise the error along with the
'name of the calling subroutine or function.
'*****************************************************************
'SOAP Error
If sc_SalesRankNPrice.faultcode <> "" Then
Err.Raise vbObjectError, str_Function,
sc_SalesRankNPrice.faultstring
'Non SOAP Error
Else
Err.Raise Err.Number, str_Function, Err.Description
End If
End Sub
Finally, proxy methods corresponding to the XML Web service's methods are generated. When you select the SalesRankNPrice XML Web service in the Web Service References dialog box, you get all of the methods that are available for this service. In this section, we will only discuss the code for theGetAll
Web method that uses complex data types. You should note that Web method signatures created by the Web Service References Tool 2.0:
- Are always declared as Public Function
- Are always prefixed by the text wsm_ followed by the Web method name
- List input parameters with a data type prefix followed by the Web method parameter
Here is the generated procedure:
Public Function wsm_GetAll(ByVal str_ISBN As String) As struct_All
'*****************************************************************
'Proxy function created from
http://www.perfectxml.net/WebServices/
SalesRankNPrice/BookService.asmx?wsdl.
'*****************************************************************
'Error Trap
On Error GoTo wsm_GetAllTrap
Set wsm_GetAll = sc_SalesRankNPrice.GetAll(str_ISBN)
Exit Function
wsm_GetAllTrap:
SalesRankNPriceErrorHandler "wsm_GetAll"
End Function
Thewsm_GetAll
method is called with the String value ISBN. Thesc_SalesRankNPrice
object uses theGetAll
method of the XML Web service. The result from the XML Web service is then returned to the calling method as astruct_All
structure as defined in the class file of that same name.
The All User-Defined Complex Data Type
The Web Service References Tool creates a proxy structure in the client application that maps to the structure of the complex data type on the Web server. For the SalesRankNPrice XML Web service, this includes thestruct_All
class that contains the following code:
...
Public AmazonSalesRank As String
Public AmazonPrice As String
Public BNSalesRank As String
Public BNPrice As String
...
The Web Service References Tool also creates theclsof_Factory_SalesRankNPrice
class, which maps classes containing user-defined types on the client to a corresponding COM object on the Web server by using a type mapper.
Note More information about type mappers can be found in the Microsoft SOAP Toolkit 3.0.
User-defined types are returned from the XML Web service as XML data and are accessed by using the IXMLDOMNode interface. Theclsof_Factory_SalesRankNPri
class contains the following code:
...
Implements IGCTMObjectFactory
Private Function IGCTMObjectFactory_CreateObject(ByVal par_WSMLNode As
MSXML2.IXMLDOMNode) As Object
Dim node As IXMLDOMNode
On Error GoTo IGCTMObjectFactoryTrap
Set node = par_WSMLNode.Attributes.getNamedItem("targetClassName")
Set IGCTMObjectFactory_CreateObject = Nothing
If Not (node Is Nothing) Then
Select Case node.nodeValue
Case "struct_All"
Set IGCTMObjectFactory_CreateObject = New struct_All
Case "struct_Prices"
Set IGCTMObjectFactory_CreateObject = New struct_Prices
Case "struct_SalesRankNPrice1"
Set IGCTMObjectFactory_CreateObject = New
struct_SalesRankNPrice1
Case "struct_SalesRanks"
Set IGCTMObjectFactory_CreateObject = New
struct_SalesRanks
End Select
End If
Exit Function
IGCTMObjectFactoryTrap:
Err.Raise Err.Number, "clsof_Factory_SalesRankNPri",
Err.Description
...
In addition to code used to map the user-defined type in thestruct_All
class, there is also code in the file for other user-defined types available for the SalesRankNPrice XML Web service.
The frmSalesRankNPrice Form
ThefrmSaleRankNPrice
form utilizes the proxy methods described above to allow the user to type an ISBN and display the Amazon sales rank and price, and the Barnes & Noble sales rank and price. The following code is invoked from thecmdGetBookData
command button:
Private Sub cmdGetBookData_Click()
Dim ComplexTypes As New clsws_SalesRankNPrice
Dim TestOutput As New struct_All
Dim strISBN As String
On Error GoTo cmdGetBookData_Click_Err
' Indicate progress to the user.
DoCmd.Hourglass True
' Clear the text boxes.
txtAMSalesRank.SetFocus
txtAMSalesRank = ""
txtAMPrice.SetFocus
txtAMPrice = ""
txtBNSalesRank.SetFocus
txtBNSalesRank = ""
txtBNPrice.SetFocus
txtBNPrice = ""
' Prompt for ISBN.
txtISBN.SetFocus
If IsNull(txtISBN) Or txtISBN = "" Then
MsgBox "Please enter an ISBN and click the button."
GoTo cmdGetBookData_Click_End
Else
strISBN = txtISBN
' Call the XML Web service.
Set TestOutput = ComplexTypes.wsm_GetAll(strISBN)
' Display the results.
txtAMSalesRank = Trim(TestOutput.AmazonSalesRank)
txtAMPrice = Trim(TestOutput.AmazonPrice)
txtBNSalesRank = Trim(TestOutput.BNSalesRank)
txtBNPrice = Trim(TestOutput.BNPrice)
txtISBN.SetFocus
End If
cmdGetBookData_Click_End:
DoCmd.Hourglass False
Exit Sub
cmdGetBookData_Click_Err:
MsgBox "Error number: " & Err.Number & " " & Err.Description
GoTo cmdGetBookData_Click_End
End Sub
First, we declare variables representing the SoapClient30 object, thestruct_All
class, and a String variable to contain the ISBN. Next, we clear the text boxes on the form and then check to see make sure that the user entered an ISBN value. If the user didn't enter a value before clicking the button, we display a message and exit the procedure. Otherwise, we set thestrISBN
variable to the value in the text box, call thewsm_GetAll
proxy method, and assign the results to theTestOutput
variable. Then, we parse the results, display the values, and exit the procedure. Notice that referencing the WSDL with the Web Service References Tool makes the objects and methods of the XML Web service available to the client application at design time. This gives you the added benefit of Microsoft IntelliSense® and syntax checking against XML Web services (also known as early binding). You can see the results from this XML Web service in Figure 3.
Figure 3. Results from the SalesRankNPrice XML Web service
The frmZipCodeResolver Form
In the following example, we will use the Zip Code Resolver XML Web service. Given a valid street address, city, and state, this service returns the proper Zip Code, Zip Code + 4, or USPS corrected address. This service exposes five methods including theCorrectedAddressXML
method, which accepts four String values as arguments:
- accessCode Use "0" or "9999" for testing purposes
- address A street address (for example, "One Microsoft Way")
- city A city name (for example, "Redmond")
- state A two-letter state postal abbreviation (for example, "WA")
The method returns the USPS address as a complex SOAP data type containing XML elements as follows:
<Street>1 MICROSOFT WAY</Street>
<City>REDMOND</City>
<State>WA</State>
<ShortZIP>98052</ShortZIP>
<FullZIP>98052-8300</FullZIP>
Using the code that the Web Service References Tool 2.0 generates, the following code builds a SOAP request, calls theCorrectedAddressXML
method, and uses the MSXML XML parser to parse the SOAP response.
Note The MSXML XML parser is included with the Office XP Web Services Toolkit 2.0 and the SOAP Toolkit 3.0.
After setting a reference to the Zip Code Resolver XML Web service, the Web Service References Tool creates the following files:
clsof_Factory_ZipCodeResolv
Contains code that maps the structure in thestruct_USPSAddress
file with the methods in the COM object on the Web server.struct_USPSAddress
Contains theUSPSADDRESS
structure withStreet, City, State, ShortZIP,
andFullZIP
variables.clsws_ZipCodeResolver
Contains code that encapsulates the ZIP Code Resolver XML Web service methods.
Briefly looking at the code generated in the clws_ZipCodeResolver class module:
...
'Dimensioning private class variables.
Private sc_ZipCodeResolver As SoapClient30
Private Const c_WSDL_URL As String =
"http://webservices.eraserver.net/zipcoderesolver/zipcoderesolver.asmx?
WSDL"
...
As with the previous example, two variables are declared representing the SoapClient30 proxy object and the URL to the XML Web service's WSDL file.
...
Private Const c_SERVICE As String = "ZipCodeResolver"
Private Const c_PORT As String = "ZipCodeResolverSoap"
Private Const c_SERVICE_NAMESPACE As String =
"http://webservices.eraserver.net/"
...
Then, other variables are declared, representing the name of the
service, the port that receives the SOAP requests, and the XML Web
service namespace, respectively.
...
Private Sub Class_Initialize()
'*****************************************************************
'This subroutine will be called each time the class is
instantiated.
'Creates sc_ComplexTypes as new SoapClient30, and then
'initializes sc_ComplexTypes.mssoapinit2 with WSDL file found in
'http://webservices.eraserver.net/
zipcoderesolver/zipcoderesolver.asmx?WSDL.
'*****************************************************************
Dim str_WSML As String
str_WSML = "<servicemapping name='ZipCodeResolver'>"
str_WSML = str_WSML & "<service name='ZipCodeResolver'>"
str_WSML = str_WSML & "<using
PROGID='MSSOAP.GenericCustomTypeMapper30' cachable='0'
ID='GCTM'/>"
str_WSML = str_WSML & "<types>"
str_WSML = str_WSML & "<type name='USPSAddress'
targetNamespace='http://webservices.eraserver.net/' uses='GCTM'
targetClassName='struct_USPSAddress'/>"
str_WSML = str_WSML & "</types>"
str_WSML = str_WSML & "</service>"
str_WSML = str_WSML & "</servicemapping>"
Set sc_ZipCodeResolver = New SoapClient30
sc_ZipCodeResolver.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE,
c_PORT, c_SERVICE_NAMESPACE
'Use the proxy server defined in Internet Explorer's LAN settings
by
'setting ProxyServer to <CURRENT_USER>
sc_ZipCodeResolver.ConnectorProperty("ProxyServer") =
"<CURRENT_USER>"
'Autodetect proxy settings if Internet Explorer is set to
autodetect
'by setting EnableAutoProxy to True
sc_ZipCodeResolver.ConnectorProperty("EnableAutoProxy") = True
Set sc_ZipCodeResolver.ClientProperty("GCTMObjectFactory") = New
clsof_Factory_ZipCodeResolv
End Sub
...
In the Class_Initialize event procedure, a concatenated String variable is declared that maps the XML Web service'sUSPSAddress
structure on the Web server to the proxy structure defined in thestruct_USPSAddress
class file. Then, the SoapClient30 proxy object is instantiated. The Class_Terminate event procedure and error handler serve the same purpose described previously.
...
Private Sub Class_Terminate()
'*****************************************************************
'This subroutine will be called each time the class is destructed.
'Sets sc_ComplexTypes to Nothing.
'*****************************************************************
'Error Trap
On Error GoTo Class_TerminateTrap
Set sc_ZipCodeResolver = Nothing
Exit Sub
Class_TerminateTrap:
ZipCodeResolverErrorHandler ("Class_Terminate")
End Sub
Private Sub ZipCodeResolverErrorHandler(str_Function As String)
'*****************************************************************
'This subroutine is the class error handler. It can be called from
any class subroutine or function
'when that subroutine or function encounters an error. Then, it
will raise the error along with the
'name of the calling subroutine or function.
'*****************************************************************
'SOAP Error
If sc_ZipCodeResolver.faultcode <> "" Then
Err.Raise vbObjectError, str_Function,
sc_ZipCodeResolver.faultstring
'Non SOAP Error
Else
Err.Raise Err.Number, str_Function, Err.Description
End If
End Sub
...
Thewsm_CorrectedAddressXml
procedure accepts four String values representing an Access code, street address, city and state. The procedure then calls theCorrectedAddressXml
method of thesc_ZipCodeResolver
object. The result is returned to the calling procedure as astruct_USPSAddress
structure.
Public Function wsm_CorrectedAddressXml(ByVal str_accessCode As String,
ByVal str_address As String, ByVal str_city As String, ByVal
str_state As String) As struct_USPSAddress
'*****************************************************************
'Proxy function created from
http://webservices.eraserver.net/zipcoderesolver/
zipcoderesolver.asmx?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_CorrectedAddressXmlTrap
Set wsm_CorrectedAddressXml =
sc_ZipCodeResolver.CorrectedAddressXml(str_accessCode,
str_address, str_city, str_state)
Exit Function
wsm_CorrectedAddressXmlTrap:
ZipCodeResolverErrorHandler "wsm_CorrectedAddressXml"
End Function
Thestruct_USPSAddress
class file contains the following code:
...
Public Street As String
Public City As String
Public State As String
Public ShortZIP As String
Public FullZIP As String
...
The Web Service References Tool also creates theclsof_Factory_ZipCodeResolv
class, which maps the returned complex data type to a generic type mapper as follows:
...
Implements IGCTMObjectFactory
Private Function IGCTMObjectFactory_CreateObject(ByVal par_WSMLNode As
MSXML2.IXMLDOMNode) As Object
Dim node As IXMLDOMNode
On Error GoTo IGCTMObjectFactoryTrap
Set node = par_WSMLNode.Attributes.getNamedItem("targetClassName")
Set IGCTMObjectFactory_CreateObject = Nothing
If Not (node Is Nothing) Then
Select Case node.nodeValue
Case "struct_USPSAddress"
Set IGCTMObjectFactory_CreateObject = New
struct_USPSAddress
End Select
End If
Exit Function
IGCTMObjectFactoryTrap:
Err.Raise Err.Number, "clsof_Factory_ZipCodeResolv",
Err.Description
...
ThefrmZipCodeResolver
form uses the following code to utilize theCorrectedAddressXml
method of the Zip Code Resolver XML Web service:
Private Sub cmdGetAddr_Click()
Dim objResolver As clsws_ZipCodeResolver
Dim objNewAddr As struct_USPSAddress
Dim str_accessCode As String
Dim str_address As String
Dim str_city As String
Dim str_state As String
Dim loc As Integer
Const TEST_ACCESS_CODE = "9999"
On Error GoTo cmdGetAddr_Click_Err
' Indicate progress to the user.
DoCmd.Hourglass True
' Set the input strings.
str_accessCode = TEST_ACCESS_CODE
str_address = txtInAddress
str_city = txtInCity
str_state = txtInState
' Clear the text boxes.
txtOutStreet.SetFocus
txtOutStreet = ""
txtOutCity.SetFocus
txtOutCity = ""
txtOutState.SetFocus
txtOutState = ""
txtOutShortZip.SetFocus
txtOutShortZip = ""
txtOutFullZip.SetFocus
txtOutFullZip = ""
' Create an instance of the XML Web service class.
Set objResolver = New clsws_ZipCodeResolver
' Create an instance of the object to hold the return.
Set objNewAddr = New struct_USPSAddress
' Call the proxy method.
Set objNewAddr =
objResolver.wsm_CorrectedAddressXml(str_accessCode, _
str_address, str_city, str_state)
' Display the return on the form.
txtOutStreet = objNewAddr.Street
' For some reason, the return City field is prefixed by a
' carriage return so need to remove it.
If InStr(1, objNewAddr.City, Chr(10)) Then
txtOutCity = Right(objNewAddr.City, Len(objNewAddr.City) - _
(InStr(1, objNewAddr.City, Chr(10)) + 2))
Else
txtOutCity = objNewAddr.City
End If
txtOutState = objNewAddr.State
txtOutShortZip = objNewAddr.ShortZIP
txtOutFullZip = objNewAddr.FullZIP
txtInAddress.SetFocus
cmdGetAddr_Click_End:
' Reset the mouse cursor.
DoCmd.Hourglass False
Exit Sub
cmdGetAddr_Click_Err:
MsgBox "Error number: " & Err.Number & " " & Err.Description
GoTo cmdGetAddr_Click_End
End Sub
The details of this code are similar to the procedure we used for the SaleRankNPrice XML Web service. The results are displayed as in Figure 4.
Figure 4. The results from the Zip Code Resolver XML Web service
The frmCurrentWeather Form
The last form we will briefly examine is thefrmCurrentWeather
form. This form accesses the WeatherRetriever XML Web service, which provides theGetWeather
method. This method accepts a Zip Code as a String value and returns a complex data type structure (struct_CurrentWeather
) consisting of four String values representing the date and time the weather data was last updated, a URL to an icon representing the current weather conditions, the current weather conditions, the direction of the barometer reading, and three Single values representing the current temperature, the current humidity, and barometer reading.
The Web Service References Tool generates the following code:
...
'Dimensioning private class variables.
Private sc_WeatherRetriever As SoapClient30
Private Const c_WSDL_URL As String =
"http://www.vbws.com/services/weatherretriever.asmx?WSDL"
Private Const c_SERVICE As String = "WeatherRetriever"
Private Const c_PORT As String = "WeatherRetrieverSoap"
Private Const c_SERVICE_NAMESPACE As String = "http://tempuri.org/"
Private Sub Class_Initialize()
'*****************************************************************
'This subroutine will be called each time the class is
instantiated.
'Creates sc_ComplexTypes as new SoapClient30, and then
'initializes sc_ComplexTypes.mssoapinit2 with WSDL file found in
'http://www.vbws.com/services/weatherretriever.asmx?WSDL.
'*****************************************************************
Dim str_WSML As String
str_WSML = "<servicemapping name='WeatherRetriever'>"
str_WSML = str_WSML & "<service name='WeatherRetriever'>"
str_WSML = str_WSML & "<using
PROGID='MSSOAP.GenericCustomTypeMapper30' cachable='0'
ID='GCTM'/>"
str_WSML = str_WSML & "<types>"
str_WSML = str_WSML & "<type name='CurrentWeather'
targetNamespace='http://tempuri.org/' uses='GCTM'
targetClassName='struct_CurrentWeather'/>"
str_WSML = str_WSML & "</types>"
str_WSML = str_WSML & "</service>"
str_WSML = str_WSML & "</servicemapping>"
Set sc_WeatherRetriever = New SoapClient30
sc_WeatherRetriever.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE,
c_PORT, c_SERVICE_NAMESPACE
'Use the proxy server defined in Internet Explorer's LAN settings
by
'setting ProxyServer to <CURRENT_USER>
sc_WeatherRetriever.ConnectorProperty("ProxyServer") =
"<CURRENT_USER>"
'Autodetect proxy settings if Internet Explorer is set to
autodetect
'by setting EnableAutoProxy to True
sc_WeatherRetriever.ConnectorProperty("EnableAutoProxy") = True
Set sc_WeatherRetriever.ClientProperty("GCTMObjectFactory") = New
clsof_Factory_WeatherRetrie
End Sub
Private Sub Class_Terminate()
'*****************************************************************
'This subroutine will be called each time the class is destructed.
'Sets sc_ComplexTypes to Nothing.
'*****************************************************************
'Error Trap
On Error GoTo Class_TerminateTrap
Set sc_WeatherRetriever = Nothing
Exit Sub
Class_TerminateTrap:
WeatherRetrieverErrorHandler ("Class_Terminate")
End Sub
Private Sub WeatherRetrieverErrorHandler(str_Function As String)
'*****************************************************************
'This subroutine is the class error handler. It can be called from
any class subroutine or function
'when that subroutine or function encounters an error. Then, it
will raise the error along with the
'name of the calling subroutine or function.
'*****************************************************************
'SOAP Error
If sc_WeatherRetriever.faultcode <> "" Then
Err.Raise vbObjectError, str_Function,
sc_WeatherRetriever.faultstring
'Non SOAP Error
Else
Err.Raise Err.Number, str_Function, Err.Description
End If
End Sub
...
These declarations and procedures are used the same way as discussed in the previous examples. TheGetWeather
method of the WeatherRetriever XML Web service is included below:
Public Function wsm_GetWeather(ByVal str_zipCode As String) As
struct_CurrentWeather
'*****************************************************************
'Proxy function created from
http://www.vbws.com/services/weatherretriever.asmx?WSDL.
'*****************************************************************
'Error Trap
On Error GoTo wsm_GetWeatherTrap
Set wsm_GetWeather = sc_WeatherRetriever.GetWeather(str_zipCode)
Exit Function
wsm_GetWeatherTrap:
WeatherRetrieverErrorHandler "wsm_GetWeather"
End Function
ThefrmCurrentWeather
form consists of a text box where the user can type a Zip Code, a button that invokes the event procedure, and a number of other text boxes for displaying the results of the XML Web service. The form also includes an Image control that displays a GIF file indicating the current weather conditions. For example, if the XML Web service returns the weather condition as Sunny
, then thesunny.gif
file is displayed. In addition, there is a text box located under the Image control that contains theIconURL
value returned from the XML Web service. This value is used in theGetImage
procedure to determine the image displayed. The OnCurrent event of thefrmCurrentWeather
form is used to set the Image control to a default GIF image as follows:
Private Sub Form_Current()
On Error Resume Next
Me![imgIcon].Picture = "C:\weather.gif"
End Sub
The following procedure is executed when the user clicks thecmdWeather
button:
Private Sub cmdWeather_Click()
Dim clsWeather As clsws_WeatherRetriever
Dim objCurrent As struct_CurrentWeather
Dim strZIP As String
Dim strURL As String
Dim strImageName As String
On Error GoTo cmdWeather_Click_Err
DoCmd.Hourglass True
Set clsWeather = New clsws_WeatherRetriever
Set objCurrent = New struct_CurrentWeather
Me![txtZIP].SetFocus
If Me![txtZIP].Value = "" Or IsNull(Me![txtZIP].Value) Then
MsgBox "Please enter a ZIP Code and click the button."
GoTo cmdWeather_Click_End
Else
strZIP = Trim(Me![txtZIP].Value)
Set objCurrent = clsWeather.wsm_GetWeather(strZIP)
Me![txtTemp].SetFocus
Me![txtTemp].Value = objCurrent.CurrentTemp
Me![txtConditions].SetFocus
Me![txtConditions].Value = objCurrent.Conditions
Me![txtHumidity].SetFocus
Me![txtHumidity].Value = objCurrent.Humidity
Me![txtBarometer].SetFocus
Me![txtBarometer].Value = objCurrent.Barometer
Me![txtDirection].SetFocus
Me![txtDirection].Value = objCurrent.BarometerDirection
strURL = objCurrent.IconUrl
strImageName = GetImage(strURL)
Me![txtIcon].SetFocus
Me![txtIcon].Value = strImageName
Me![cmdWeather].SetFocus
End If
cmdWeather_Click_End:
DoCmd.Hourglass False
Exit Sub
cmdWeather_Click_Err:
MsgBox "The service is busy. Please try again later."
GoTo cmdWeather_Click_End
End Sub
In addition to the tasks we have described in previous examples of determining whether the user entered a Zip Code before clicking the button, calling the proxy method of the XML Web service, and assigning the results to the various text boxes for display, this procedure also calls theGetImage
procedure. TheGetImage
procedure accepts the IconURLString value, which contains a URL containing a GIF file name that provides a visual indication of the current weather conditions. TheGetImage
procedure strips this file name from the IconURL argument, uses a Select Case . . . End Select statement to evaluate the extracted file name, and then returns a reference to a local GIF file, back to thecmdWeather_Click
procedure. This process is useful because displaying a local file in an Image control is much easier and requires less code than using a URL.
Private Function GetImage(ByVal IconUrl As String) As String
Dim strImageType As String
strImageType = Right(IconUrl, Len(IconUrl) - (InStr(1, IconUrl,
"/images/") + 7))
Select Case strImageType
Case "partcloud.gif"
GetImage = "C:\pcloudy.gif"
Case "sunny.gif"
GetImage = "C:\sunny.gif"
Case "cloudy.gif"
GetImage = "C:\cloudy.gif"
Case "rainy.gif"
GetImage = "C:\rain.gif"
Case Else
GetImage = "C:\weather.gif"
End Select
End Function
In order for the image to be updated each time the XML Web service returns a new result, we include the following code in the OnLostFocus event of thetxtIcon
text box:
Private Sub txtIcon_LostFocus()
On Error Resume Next
Me![imgIcon].Picture = Me![txtIcon]
End Sub
The results of using this XML Web service are displayed in Figure 5.
Figure 5. The results of the WeatherRetriever XML Web service
Most of the XML Web services we have used in this article also include other methods that you should explore. In addition, the XML Web services described here represent just a very small number of the XML Web services that exist. That number is growing daily as more individuals and companies see the advantage to using XML Web services for extending their services.
Conclusion
In this article, we demonstrated using a sample Microsoft Access 2002 database to access a number of XML Web services using both simple and complex data types. The database used the Web Services References Tool 2.0, which is provided with the Office XP Web Services Toolkit 2.0. By exploring the code and techniques used in this article, you will be able to incorporate the power of XML Web services into your own applications.