Introduction

Publishing and Using Web Services

If you haven't worked through the complete Quick Start section of the Tutorials, we suggest that you at least work through the following sections:

  • Creating Your First Web Service

  • Using Your First Web Service

  • Server Side Web Services

  • Client Side Web Services

  • Building Server Side Web Services

  • Building Client Side Web Services

  • Handling XML Data

Introduction

Web Services provides a mechanism for making application logic accessible using standard Internet protocols. A Web Service allows programs to exchange data and access application logic over the Internet. Central to the to the concept of web services is neutrality. Web service must be platform neutral, protocol neutral and language neutral.

The standard for web service information exchange is SOAP (Simple Object Access Protocol). W3C (http://www.w3.org/TR/soap11/) describes SOAP as follows:

“SOAP is a lightweight protocol for exchange of information in a decentralized, distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined datatypes, and a convention for representing remote procedure calls and responses

While SOAP can potentially be used with other protocols, the current focus of SOAP within the industry and, therefore, within Visual DataFlex is using SOAP over HTTP (i.e., over the Internet).

The focus of Web Services within Visual DataFlex will be the exchange of information based on remote procedure calls. Restated, a web service allows you to create a function that can be called remotely, over the Internet, by any application in the world. This function on the server can reside on any platform and be written in any language. The application calling the function can reside on any platform and be written in any language.

Web services are created in an application that runs on a web-server. They are “called” by a remote application. The web-service on the server will be referred to as a Server Side Web Service. The application calling the service does this by calling a method in a local object that is referred to as a Client Side Web Service. The client is responsible for making the actual remote request.

Visual DataFlex provides support for both Server and Client side web services. While this means that you can use the Visual DataFlex Web-application server to create web services that can be accessed by any Visual DataFlex windows application, it is important to understand the use of web-services goes far beyond this capability. On the server side, a Visual DataFlex web service can be accessed by any application. On the client side, a Visual DataFlex application can access any web-service.

Ease of Use

One of the primary goals of Web Service implementation in Visual DataFlex was simplicity. A developer should be able to create and use web services without needing to understand all of the underlying complexities that make them work. If you can create a function, you can create a web-service. If you can call a function, you can access a web service.

If you are new to web services, you may wish to jump right in and start building and using web services. Start by creating a web-service within a web application. You should be able to do this without having to deal with any of the underlying complexities that comprise web-services (SOAP, XML, WSDL, Schemas, Serialization, etc.).

After you’ve created a web-service and tested it using the test service pages, try using this service by building a client web-service class and object. You will create your class by pointing to the web-service description and telling Visual DataFlex to create a sub-class. An object based on this class can then be dropped into your application and can then access the service operations just like you would access any method within your application. Again, this can all be done without needing to deal with the underlying implementation.

After you’ve succeeded connecting to the web-service you created, you may wish to find some other web-service and try connecting to that. A good place to find web-services is x-methods (http://www.xmethods.net).


Server Side Web Services

In Visual DataFlex, a web-application consists of web-objects (WOs). A web object can be a web-browser object (WBO) or a web-service object (WSO).

WBOs – Web Browser Objects

WBOs are used to communicate with browser type of clients such as Internet browsers, PDAs and WAP phones. These client browsers make requests to your web-server by requesting active-server pages (ASP). These are file names with an “.asp” extension. The ASP page is used to build your response page. The page is built by making calls into WBOs within your web-application. The response sent back to the browser will usually be in HTML format but can be in other formats such as XML or WML. WBOs are always called by code embedded in your ASP page. Therefore, when building browser style web-applications you will be programming in two areas – in the ASP page and in the WBO.

WBOs are created within the Studio by creating a Web Browser Object component. This creates a standalone WBO component based on the cWebBusinessProcess class. You will also need to create an ASP page that accesses the WBO. Because of the ASP/WBO dependency, wizards are provided that allows you to create WBOs and ASP pages at the same time.

WSOs – Web Service Objects

WSOs are used to communicate with web-service clients. A web-service client will be part of some remote application. When needed, the application will make a call to the web-service client and the client will make the request to a web service. If this web service is part of a Visual DataFlex web-application, the request will be sent to as a function call within the WSO. This function will do whatever it needs to do, and return information to the client. Because a web-service is an application-to-application exchange of data, there is no need to use ASP. When building web-service based web-applications you will be programming in just one area – the WSO.

A single web-application supports both WBOs and WSOs. A single web-application can support multiple web-services (one service per WSO). A single WSO, can support multiple operations (each operation is a function).

WSDLs – Service Descriptions

It is expected that any web-service provide a description of its service. This is done by providing a formal service description document that describes exactly how the service should be accessed. This document is called a WSDL document (Web Service Description Language) and is defined by W3C at http://www.w3.org/TR/wsdl.

A WSDL document tells you everything you need to know about a web-service. It tells you where the service is located, how it is accessed and what operations are available for the service. It defines the parameters and data-types for each operation. It also specifies exactly how the SOAP request and response should be encoded.

A WSDL document is an XML file. While it is human readable, it is really designed to be written (generated) and read (parsed) by a computer. On the server side, the Visual DataFlex web-application server generates WSDL documents. On the client side, Visual DataFlex contains a parser that reads WSDL documents and creates client web-service classes.

See Also

Publishing and Using Web Services


Client Side Web Services

Within a Visual DataFlex windows application, a web service is accessed by:

  1. Generating a sub-class that provides access to a web-service.

This class, which will be automatically generated by accessing to the web-service’s description will contain a method interface (function name and parameters) that matches the interface of the actual web-service.

  2. Creating an object within your program that is based on this sub-class.

This is accomplished by selecting the web-service class from the Studio’s control palette and dropping it into your view.

  3. Calling the function within this client object.

The object will convert your function into a SOAP request and send it to the server. When it gets a response from the server it will unpack the SOAP response and place the data into the function’s return value.

Creating a Client Web-Service Class

A new class, cClientWebService, is used as the basis for all client web-services. This class knows how to handle generic SOAP messages. Each web-service has its own definition and therefore each web-service will be represented on the client side as a sub-class, based on cClientWebService. These custom classes contain functions that correspond to the functions that exist in the actual service.

A tool, the Web-Service Client Class Generator is provided for automatically creating client web-service classes. This class generator requires that you provide it with the location of a web-service’s description (its WSDL location). The tool will parse the WSDL document and create a sub-class based on that information. It will create the class and all additional files required to integrate the class directly in the Studio so that it can be accessed from the Studio’s Control Palette.

Adding a Client Web Service Object to your Application

Once a web service client sub-class has been created it can be added to any program in the same manner that any object is added to a Visual DataFlex application. You will need to find your web-service class in your Control Palette, grab it and drag and drop it into your component.

Calling a Web-Service

If you look at the client web-service object that was created you will see that the service’s interface is shown as part of the object’s documentation. These interfaces will appear as standard functions consisting of a function name, parameter data-types and names, and a return data-type. A web service is called, by sending a message to this object (i.e., you just call the function). The object will take this local function call, turn it into a proper SOAP request and make the needed HTTP request to the server. The server will process the request and send back a SOAP response. The client object will take this response, parse it and set up the return value or, if needed, handle any error messages. As a developer, you will see none of this. You will simply be calling a method within an object and getting return value.

See Also

Publishing and Using Web Services


Building Server side web services

This section will show you how to create a web-service for the Visual DataFlex web-application server. At this point, we assume that you have installed Visual DataFlex, loaded the Studio and are trying these steps out as you go along. The process is quite simple and in most cases is much easier to actually see than it is to document.

  • Getting Started

  • Creating a Web Service Object

  • Compiling and Testing your Web Service

  • Web Services and the Debugger

  • Supported Data-types in Server Web Services

See Also

Publishing and Using Web Services


Getting Started

Server side web services are provided as part of Web-Application Server. This is the same server and requires the same development environment needed to build browser-based web-applications. Web-applications require that your development and, eventually, your deployment environments are running Microsoft’s IIS Internet server. Before proceeding you might want to make sure that your development environment supports IIS. You can do this by trying to load and run the web-application sample. Make sure this is working properly before you try to create a web-service

You will be creating your web-services within a web-application (webapp.src) that resides within a workspace. Before you create a web-service component you need to make sure that the web-application exists. If you are adding a web-service to an existing web-application, that component already exists (Note that you are allowed to add both Web Service Objects and Web Browser Objects to a single web-application.) If you have not yet created a web-application you may do so by:

  1. In the Studio, select the "File/New/Project…" menu option.

  2. Select "Web Project"

  3. You will be asked to select a name for your Virtual Directory (you can use the default provided).

  4. Provide a description for your application and save it.

You are now ready to build a Web Service.

See Also

Building Server Side Web Services


Creating a Web Service Object

Creating a web service WSO component consists of the following steps:

  • Create a New WSO component

  • Create your functions (operations) that you wish to make public

  • Publish these functions

  • Document the operations and the service

  • Set the name of the service

  • Save the component and add it to your web-application

Here are these same steps, described in more detail:

  1. In the Studio, select the “File/New/Web Object…” file menu option. You may also access Web Objects using the New button in the toolbar.

  2. Select “Web Service Object”. This will create a new Web Service component.

  3. Using the Studio’s code explorer, open the source inside of your Web Service object and write your code. To keep it simple, we suggest that you create a simple “Hello World” function to start with. This function may look like the following:

Function Hello string sName returns string

string sReply

Move ("Hello," * sName - ", how are you today") to sReply

Function_Return sReply

End_Function

Note that this is a very simple example. A WSO object is a business process object and is capable of performing sophisticated operations. You can create data-dictionary object structures within the WSO and use web-service operations to store and retrieve data from your DDOs. You can create additional private processing methods within your WSO, which can be called by your public web-service operations. Additionally, you can choose to have your public operations access program logic outside of your WSO. Think of a web-service operation as a portal into your application, your application logic and your application data.

  4. 4. A WSO may contain many functions and not all of them should be exposed as a web-service. You expose a web-service method by publishing it. You do this by finding that method in the Code Explorer and selecting publish from the right click, context menu. Alternatively you can also add the Published meta-data tag manually. For example:

{ Published = True }

Function Hello string sName returns string

string sReply

Move ("Hello," * sName - ", how are you today") to sReply

Function_Return sReply

End_Function

  5. 5. You may create an optional but recommended comment for any web-service function. This comment will be published as part of the service’s description in the WSDL file. The comment is specified using the Description meta-data tag immediately above the function/procedure. For example:

{ Published = True }

{ Description = "This function says hello" }

Function Hello string sName returns string

string sReply

Move ("Hello," * sName - ", how are you today") to sReply

Function_Return sReply

End_Function

  6. You will want to create a description for the entire web-service to be published as part of the service’s description. You can do this by finding the following source code and replacing it with meaningful information. Note that this source is broken up into multiple lines to demonstrate how to create long, yet readable description within the edit area.

Set psDocumentation to ;

("Visual DataFlex Web Service .... " +;

" ... " + ;

"documentation")

  7. You need to set the Service name. This name uniquely identifies the service within your application and is used by clients to access the service. For example, if the name of your service was “HelloService” in an application whose virtual directory was http://localhost/MyApplication the service would be accessed with the URL http://localhost/MyApplication/HelloService.wso. The name is set with the psServiceName property in the Studio’s property page. The default name is tempService, which you will want to change.

  8. Save the component. Before you can test or use this service it must be added to your application. As you save the WSO you will be allowed to automatically add the WSO component to your WebApp.src application. Do so.

See Also

Building Server Side Web Services


Compiling and Testing your Web Service

After you have created your web-service you need to compile and test it. You should do this by selecting Debug -> Run from the menu in the Studio.

Note

All Visual DataFlex web-services can be accessed using a browser. The browser will display a test page that provides information about your service and all of its operations. It lets you look at the Service description (the wsdl file) and it allows you to test the service.

The test page is generated by pointing a browser’s URL to a location consisting of your virtual directory, your web-service name (defined by the WSO’s psServiceName property), and the extension “.wso”. For example, if the name of your service is “HelloService” and your virtual directory is http://localhost/MyApplication the service test page is accessed with http://localhost/MyApplication/HelloService.wso.

The test page is used for more than debugging. Other client applications will use this page to provide information about your service. One of the options on the test page is the ability to view the service description. This displays the service’s WSDL file. This is an important function as it provides access to the service’s definition. This will be used to clients to figure out how to use the service. For example, within Visual DataFlex, the client web-service class generator will use this WSDL to build the client web-service class.

The WSDL page can be explicitly loaded by appending a “?WSDL” to your web-service’s URL (e.g. http://localhost/MyApplication/HelloService.wso?WSDL).

The test pages and the WSDL definition are generated dynamically while the web-application is running. This means that your service definition is always up to date. It also means, that you do not need to concern yourself with creating and maintaining your service definitions. The web-application server does this for you automatically.

How a Web Service is Located

As mentioned above, a web service is located by pointing to a URL address on your server (e.g. http://localhost/MyApplication/HelloService.wso.). Normally a browser-based web-application will be accessed by pointing to a file name with an .asp, .htm, .html or .wml extension. You will notice that the web-service file name contains a .wso file extension. The .wso file extension is registered within IIS to have a special meaning. When a .wso file is requested the server redirects this request to the DataFlex web-service server, bypassing all normal asp and html processing.

If you look within your virtual directory (your appHtml directory within your workspace) you will see that the .wso file actually exists (e.g. look for ..\appHtml\HelloService.wso). This is a small file that contains all of the information needed to direct a web-service request to the proper WSO object and to generate your test and WSDL pages. This is the file, which when accessed over the web, connects a SOAP request to the web-service object in your web-application.

The name of this .wso file is important. Its name is determined by the value you set in your WSO’s psServiceName property. Each WSO within a single web-application should have a unique psServiceName. (Note that the WSO’s object name is purposefully not used for purpose. The service name is defined in your WSDL description and is used by clients to build client web-service classes. You want to be able to control the name of a service.)

You normally do not need to concern yourself with the .wso file as the Studio maintains it automatically. After a successful compile, all .wso files are generated as needed. It is important to note that the automatic maintenance of this .wso file only occurs if you compile your web-application within the Studio. If you compile your web-application outside of the Studio, which is not recommended, you will need to maintain the .wso file yourself.

To summarize, a web-application may contain multiple web-services. Each web-service is handled by a single WSO object. For each WSO in your application’s appSrc area, there must be a corresponding .wso file in your appHtml area. Each of these .wso files must have a unique name. The name is maintained in the WSO’s psServiceName property. As long as you set a proper psServiceName, everything else will be taken care of for you.

See Also

Building Server Side Web Services


Web Services and the Debugger

When a web-service component is compiled and run from within the Studio, it is run in debug mode. You will typically debug a web-service by placing a breakpoint within the function you wish to test. Debugging of web-services should be simple and straightforward. For more information, see Debugging.

See Also

Building Server Side Web Services


Supported Data-types in Server Web Services

Web service parameters may consist of any of the following:

  • Fundamental data types - these are the built in simple data types (e.g. string, integer)

  • Struct data types - these are custom data types created using this struct command (e.g. tMyOrder)

  • Arrays - these can be arrays of fundamental or struct data types. (e.g. string[], integer[][], MyOrder[])

  • XmlHandle - this is a special type that indicates that the data is passed as XML

Structs, Arrays and XmlHandle data types can only be used with Document style web services (pbDocumentStyle = true).

Fundamental Data-types

The following fundamental DataFlex data-types can be used as parameters in web-services:

String | Number | Date | Integer
BigInt | Real | Boolean | Time
DateTime | Float | Char | UChar
Short | UShort | UInteger | UBigInt
Currency | Decimal |  |

Any of these data-types may be passed or returned in a web-service. All of these data-types will map to an appropriate XML data-type as defined by the XML schema definitions. It is not expected that you will need to use most of these data-types. As with any DataFlex application, you will primarily use String, Number, Date and Integer.

Here are several very simple web-services operations using various data-types:

{ Published = True }

Function Echo String echoString Returns String

Function_Return echoString

End_Function

{ Published = True }

Function SayHello String sName Returns String

String sReturn

Move ("Hello," * sName) to sReturn

Function_Return sReturn

End_Function

{ Published = True }

Function TestDateTime DateTime dDateTime Returns String

String sReturn

Move ("The datetime in VDF locale is" * string(sDateTime) ) to sReturn

Function_Return sReturn

End_Function

Struct Data-types

A web service parameter may be a custom defined type created using the struct command. Using struct parameters allows you to pass and return complex data (e.g. an order), as a single parameter. The struct members may consist of any of the allowed fundamental data types or other structs. Struct members may be defined as arrays.

This sample shows how to define and return struct data.

struct tCustomerInfo

integer iCustNumber

string sName

string sCustAddress

string sCity

string sState

string sZip

string sPhoneNumber

string sFaxNumber

string sEmailAddress

real rCreditLimit

real rPurchases

real rBalance

string sComments

string sStatus

end_struct

:

{ Published = True }

Function GetCustomerInfo integer iCustNum Returns tCustomerInfo

tCustomerInfo CustomerInfo

// this finds the customer and fill the struct data

Get CustomerInfo iCustNum to CustomerInfo

Function_Return OneCustomer

End_Function // GetCustomerInfo

The following example is passed a more complex struct parameter that contains a member that is, itself, an array of structs.

// Order Detail

struct tOrderDet

string sItemID

integer iQty

real rUnitPrice

real rPrice

end_struct

// Order

struct tOrder

integer iOrderNumber

integer iCustNumber

date dOrdDate

string sTerms

string sShipVia

string sOrderedBy

string sSalesPerson

real rOrderTotal

tOrderDet[] ArrayOfDetails

end_struct

:

{ Published = True }

Function SaveOrderInfo tOrder TheOrder returns Boolean

Boolean bSuccess

Get SaveTheOrder TheOrder to bSuccess

Function_Return bSuccess

end_Function

Arrays

Any web service parameter may be defined as an array. Arrays may be based on fundamental data types or struct types. Arrays may be single or multi-dimensional. Note that not all web service clients are capable of supporting multi-dimensional arrays.

This sample is passed an array of customers numbers and returns an array of struct customer information.

{ Published = True }

Function SelectedCustomerInformation integer[] iCustomers returns tCustomerInfo[]

tCustomerInfo[] Customers

integer i iCustomerCount

Move (SizeOfArray(iCustomers)) to iCustomerCount

For i from 0 to (iCustomerCount-1)

// this finds a customer and fills an array element of struct data

Get CustomerInfo iCustomers[i] to Customers[i]

Loop

function_return Customers

end_function

XmlHandle Data-type

A special data-type, XmlHandle may be defined as a parameter. The XmlHandle data-type should only be used with web-services. It is used when you define a function’s parameter or return data-type.

Function DelCustomerXMLList XmlHandle CustomerList Returns XmlHandle

Defining this data-type in a web-service function indicates that the data being passed and returned is an object handle pointing to an XML Dom object (based on the cXmlDomDocument class). This provides an easy mechanism for passing data as pure XML. Within your program you treat an XmlHandle data-type exactly the same way you would treat any object handle. The object can be parsed and processed using the standard methods provided for handling XML DOM objects.

The one important distinction about this data-type is that the VDF web-services module will automatically handle the disposal of these objects when they are no longer needed. You do not need to destroy these objects yourself.

For example, this web-service operation is passed an XML document containing customer information. The service will search for customers to be deleted and attempt to delete these based on the rules in the data-dictionary. It will then return an XML document containing a list of remaining customers. Notice that the XML data is passed in and out as objects.

{ Published = True }

Function DelCustomerXMLList XmlHandle CustomerList Returns XmlHandle

Integer bOk i iItems

Handle hoRoot hoList hoCust hoWrapper hoXml1 hoRoot1

String sDel sNumber

Handle hoCustomerDD hoXML

Move Customer_dd to hoCustomerDD

If not CustomerList function_return 0

Get DocumentElement Of CustomerList To hoRoot

// create node list of all customers

Get FindNodeList Of hoRoot "Customer" To hoList

Get NodeListLength Of hoList To iItems // number of items in our node list.

Decrement iItems

// go through array looking for customers to delete

For i From 0 To iItems

Get CollectionNode Of hoList i To hoCust

// if attribute "Delete" is "Y" we will delete it

Get AttributeValue Of hoCust "Delete" To sDel

If (sDel="Y") Begin

// attempt to delete customer

Get ChildNodeValue Of hoCust "Number" To sNumber

Send Clear of hoCustomerDD

Move sNumber to Customer.Customer_number

Send Find of hoCustomerDD eq 1

If (found) Begin

Send Request_delete of hoCustomerDD

If not (err) begin

Get RemoveNode Of hoRoot hoCust To hoCust

End

End

End

//

Send Destroy Of hoCust

Loop

Send Destroy Of hoList

Function_Return CustomerList

End_Function

Using XmlHandle versus Using Struct/Array Data-types

Passing data as pure XML has advantages and disadvantages. This provides a mechanism for passing and returning complex data. There are times when this type of complex data is most efficiently processed as an XML DOM object.

The disadvantage of using XML as a parameter is that the data is not fully defined within the WSDL description. The WSDL document simply knows that the data is a well-formed XML document. A second disadvantage of passing XML is that the developer on the server and on the client will have to parse the XML data themselves.

If you need to pass complex data that is fully defined within the WSDL description, you can pass the parameters as structs and arrays. In general, it is easier to work with complex data as structs and arrays. The above example could easily be rewritten to use an array of structs as follows:

Struct tCustomerList

integer iCustomerNumber

string sCustomerName

Boolean bDelete

End_Struct

:

{ Published = True }

Function DelCustomerXMLList tCustomerList[] CustomerList Returns tCustomerList[]

tCustomerList NewCustomerList

Integer i iCustomerCount iNewCount

Boolean bWasDeleted

Move Customer_dd to hoCustomerDD

Move (SizeOfArray(CustomerList)) to iCustomerCount

// go through node list looking for customers to delete

For i From 0 To (iCustomerCount-1)

If CustomerList.bDelete begin

// attempt to delete customer

Send Clear of hoCustomerDD

Move CustomerList.iCustomerNumber to Customer.Customer_number

Send Find of hoCustomerDD eq 1

If (found) Begin

Send Request_delete of hoCustomerDD

Move (not(err)) to bWasDeleted

End

End

Else Begin

Move False to bWasDelete

end

if not bWasDeleted

Move CustomerList[i] to NewCustomerList[iNewCount]

Increment iNewCount

end

Loop

Function_Return NewCustomerList

End_Function

Passing Parameters By Reference

A web service method may pass and return information by-reference. A by-reference parameter is referred to as an in/out parameter -the same parameter is used to pass data in and data out. A by-reference parameter is defined by using the BYREF keyword in the method declaration.

The following sample passes an order as a BYREF parameter. The order is passed in, saved, refreshed and then passed back to the caller. In addition, the normal return parameter is used to return a Boolean indicating the status of the save.

{ Published = True }

Function SaveOrderInfo tOrder BYREF TheOrder returns Boolean

Boolean bSuccess

Get SaveTheOrder TheOrder to bSuccess

If bSuccess begin

Get RefreshTheOrder to TheOrder

end

Function_Return bSuccess

end_Function

Note:

The Visual DataFlex client web-service parser and class handles in/out parameters properly. However, many web-clients are not capable of supporting in/out parameters. If you wish to make a web service available to the widest number of clients, you may want to avoid using by-reference methods. With the availability of structs, there is little reason to use in/out parameters.

See Also

Building Server Side Web Services


Building Client Side Web Services

This section will show you how to create a client web-services for a Visual DataFlex windows-application. At this point, we assume that you have installed Visual DataFlex, loaded the Studio and are trying these steps out as you go along.

  • Getting Started

  • Creating a Client Web Service Class

  • Using a Client Web Service in a Component

  • Supported Data-types in Client Web Services

  • Handling Errors

  • Client Web Services and the Debugger

  • Testing a Client Web Service

See Also

Publishing and Using Web Services


Getting Started

Client side web-service access is provided as part of windows-application framework. To be able to create and access web-services your Visual DataFlex application must have Internet access. Web-service client access will be added to an application by:

  • Finding a Web-Service description on the web (i.e., locating a service’s WSDL).

  • Using the Web Service Client Class Generator, point to the WSDL and build a new class that represents the service.

  • Add the client service to any application by creating an object based on this client class (a drag and drop operation)

  • Calling the operation within the object passing and return data as required.

The easiest way to get started is to build a web-service client for a web-service created using the Visual DataFlex web-application server. Doing this will allow you to see the entire story. This allows you to build a service, view its description (the WSDL), see how it is modeled as a client class, and see how it is added and used within your application. If you’ve already created a web-service on your development machine, that web-application’s service should be running and waiting to be used.

See Also

Building Client Side Web Services


Creating Client Web Service class

Creating a Client Web Service Class

Before you can create a web-service client class, you need to locate the service’s WSDL file. You can do this by loading your Internet Browser and pointing to a WSDL file. Any service available on the web should have a mechanism for locating its WSDL. For an example of this, visit x-methods (http://www.xmethods.net).

If you are testing a Visual DataFlex web-service, the convention for locating the service (e.g. http://localhost/MyApplication/HelloService.wso.)and its WSDL has already been discussed (e.g. http://localhost/MyApplication/HelloService.wso?WSDL).

Once you’ve located your WSDL in your browser, you are going to want to enter the URL into the client class generator. It might be a good idea to mark and copy the URL.

Within the Studio, select File -> New -> Class from the menu, then select Client Web Service Class. When the class generator is loaded, enter (or paste) the WSDL name into the form labeled “WSDL URL:” Press the “Parse” button. The class generator will now locate the WSDL, load it, parse it, and determine how it should be represented as a Visual DataFlex class.

You now need to save this class and add it to the Studio. Press the “Generate Class” button. This will invoke a dialog that allows you to determine the class name and a group name in your class palette.

You are allowed to regenerate classes. For example, if your server web-service changes, you will need to generate the class again. If the generator sees that you are generating a duplicate class it will warn you and allow you to overwrite the existing class definition.

This is all you need to do to create a web-service client. The class is now created and available for use in your project. At this point, you can choose to create additional clients or you can close the class generator and use the client in your application.

See Also

Building Client Side Web Services


Using a Client Web Service in a Component

Once a client web-service class is created, you will use it by creating object instance of this class in your program. Load an existing view or create a new view. Open the Class Palette and locate the web-service component in the group where you placed it.

Find the component you want and drag it into your view. You have now created an object based on this class.

Load the code explorer and click on the new object. The commented source code for this object will appear and provide you with useful information. These comments may look like the following:

// Web Service Class is defined in cWSHelloService.pkg

//

// Interface:

//

// Function wsHello string sFirst string sLast returns string

// Function wsGoodybe string sFirst string sLast returns string

//

// phoSoapClientHelper

// Setting this property will pop up a view that provides information

// about the Soap (xml) data transfer. This can be useful in debugging.

// If you use this you must make sure you USE the test view at the top

// of your program/view by adding: Use WebClientHelper.vw // oClientWSHelper

//Set phoSoapClientHelper to oClientWSHelper

These comments tell us that the service supports two operations, wsHello and wsGoodbye and that these are passed two strings and return a string. You may also wish to look at the actual client class. The class package name is listed. You can easily open this class by moving your cursor over the name and selecting “Open File Under Cursor” from your context menu. The class will contain all the code generated by class generator. If the WSDL contained comments and descriptions, these will all be listed in the class.

To use the object in your program you need to send a message to it. For example, you could create an OnClick method in your button that calls a web-service operation as follows:

Procedure OnClick

String sFirst sLast sReply

Get Value of oFirst to sFirst

Get Value of oLast to sLast

Get wsHello of oWSHelloService sFirst sLast to sReply

Set Value of oReply to sReply

End_Procedure // OnClick

You have now accessed a web-service within your application.

All client web-service methods are prefaced with “ws”. This is done to insure that the name of a method does not collide with any reserved words within your existing application. It also makes it easy to recognize, that calls within your application to “ws” methods are calling web-services.

All client web-service class names are prefaces with cWS. This is done to insure that there is no class naming collisions. This also makes it easy to locate and identify client web-service classes.

See Also

Building Client Side Web Services


Supported Data-types in Client Web Services

Client web services have the same capabilities as server web services. The parameters may consist of any of the following:

  • Fundamental data types - these are the built in simple data types (e.g. string, integer)

  • Struct data types - these are custom data types created using this struct command (e.g. tMyOrder)

  • Arrays - these can be arrays of fundamental or struct data types. (e.g. string[], integer[][], MyOrder[])

  • Handle - this is a special type that indicates that the data is passed as XML

When a client web service class is created the class generator will recognize if structs or arrays are defined in the service definition. If structs are needed, they will be created in your class package by the class generator. The name of the struct will be prefaced with the tWS prefix to indicate that the struct is defined within a web service. When you call this web service, you call it passing and returning the struct data types and arrays as needed.

The following example assumes that the web-service returns an array of structs of tWSCustomer type. Its interface would appear as follows:

// Interface:

//

// Function wsGetCustomers returns tWSCustomer[]

It can be called and used as follows:

Procedure OnClick

tWSCustomer[] ArrayOfCustomer

Integer iCust iCustomers eStatus

Get wsGetCustomers of oWSCustomerService to ArrayOfCustomer

Get peTransferStatus of oWSCustomerService to eStatus

If (eStatus = wssOK) begin

Move (SizeOfArray(ArrayOfCustomer)) to iCustomers

For iCust from 0 to (iCustomers-1)

Send ProcessOneCustomer ArrayOfCustomer[iCust]

Loop

End

End_Procedure // OnClick

By Reference Parameters in a Client Web Service

If the web-service you are calling uses in/out parameters (where the same parameter is used pass data in and data out), your client will support this by using the BYREF keyword in your method. You will see this in your method declarations. Here is an example of a web service that has an in/out parameter declaration:

// Interface:

//

// Function wsSaveOrder tOrder BYREF MyOrder returns Boolean

If BYREF is used you must call the method using the by-reference parameter passing syntax. This is done by placing the variable within the “(&” “)” markers (e.g. (&MyParameter) ). The above method would be called as follows:

Procedure OnClick

tWSOrder TheOrder

Boolean bOk

Integer eStatus

Get wsSaveOrder of oMyWebService (&TheOrder) to bOk

Get peTransferStatus of oWSCustomerService to eStatus

If (eStatus = wssOK and bOK) begin

Send ProcessOneOrder TheOrder

End

End_Procedure // OnClick

While In/Out parameters are not usually used in web services, they are fully supported.

See Also

Building Client Side Web Services


Handling Errors

Errors can occur for any number of reasons. If the request cannot find the service, an error will occur. If the request makes it to the server but the server rejects it an error will occur. If the SOAP server detects an error it should return a soap response that contains a SOAP fault. This will contain a description of the problem. Any error will be reported as a standard DataFlex error. If the error is a SOAP Fault error, the error description provided by the service will be displayed.

The property peTransferStatus can be tested after a call to see if your web-service call succeeded. If the property’s value is wssOk, the call succeeded. All possible, and some less desirable, values for peTransferStatus are:

wssOk | Request succeeded
wssHttpRequestFailed | Http request failed
wssBadRequest | Bad or missing data sent
wssInvalidContentType | Invalid contentType received
wssNoData | No data was received
wssNotXml | Received data not in proper XML format
wssNotSoap | Received XML data not in proper Soap format
wssInvalidSoap | Received SOAP data not formatted according to service description
wssSoapFault | Soap Fault Returned. Fault-code returned in psFaultCode Fault-description returned in psFaultString

You can use this status to properly handle failed service calls. For example:

Procedure OnClick

string sFirst sLast sReply

Integer eStatus

Get Value of oFirst to sFirst

Get Value of oLast to sLast

Get wsHello of oWSHelloService sFirst sLast to sReply

Get peTransferStatus of oWSHelloService to eStatus

If (eStatus = wssOk) begin

Set Value of oReply to sReply

End

Else begin

Set Value of oReply to "Error"

end

End_Procedure // OnClick

Under some circumstances you may wish to trap an error and handle it yourself. You can suppress errors by setting the client web-service property pbSuppressLastError to true. When true, errors are not reported and it is up to you to determine how to handle the error. If peTransferStatus is not wssOk, you can manually generate an error by getting the error text for the last error and creating your own error. The error text for any error status is obtained by sending the TransferErrorDescription message. For Example:

Procedure OnClick

string sFirst sLast sReply

string sError

Integer eStatus

Get Value of oFirst to sFirst

Get Value of oLast to sLast

Get wsHello of oWSHelloService sFirst sLast to sReply

Get peTransferStatus of oWSHelloService to eStatus

If (eStatus = wssOk) begin

Set Value of oReply to sReply

End

Else begin

// we know we have an error and we know the type.

// Get the error message for this error

Get TransferErrorDescription eStatus to sError

Set Value of oReply to sError

end

End_Procedure // OnClick

Under certain circumstances you may need to see the actual SOAP requests and responses to determine a source of errors. A helper object is provided to do that and is described below. In addition, the client object maintains the XML request, response and return object of the last call. Those are maintained as XML DOM objects and are pointed to by the properties phoSoapRequest and phoSoapResponse. These are for advanced use only.

See Also

Building Client Side Web Services


Client Web Services and the Debugger

Your test view containing your client web-service will be run under the control of the debugger. You will typically debug a client web-service by placing a breakpoint on the line of code that makes the web-service function call. Alternately, you could open the client web-service class package (e.g. cWSHelloService.pkg) and place breakpoints within the appropriate functions in the class. This lets you make sure that the call is actually being made and that the parameters passed and returned are correct. If you have unexpected results, you could then step into the web-service and follow the entire process of creating an XML SOAP request, invoking the HTTP request, and parsing the SOAP response. While you could do this, you might find it much easier to use the Client Test View Helper described below.

See Also

Building Client Side Web Services


Testing a Client Web Service

A special soap client helper view can be used to allow you to see what is happening with a soap request. This helper displays a view that shows you the soap request, the soap response, the transfer (error) status, parameters, the return value and more. This purpose of this view is two-fold – it helps you debug soap client calls and it provides a great way to learn about web-services.

It is not expected that you would ever use this in a deployed application.

The comment code in your client object provides all of the information needed to use this helper object.

// phoSoapClientHelper

// Setting this property will pop up a view that provides information

// about the Soap (xml) data transfer. This can be useful in debugging.

// If you use this you must make sure you USE the test view at the top

// of your program/view by adding: Use WebClientHelper.vw // oClientWSHelper

//Set phoSoapClientHelper to oClientWSHelper

To use this helper you need to:

  1. Copy the code: “Use WebClientHelper.vw” and paste it in the top of your component source code.

  2. Uncomment the line: Set phoSoapClientHelper to oClientWSHelper

When you do this, every web-service request to this client will cause a helper view to be activated showing you what is happening.

To disable this helper view, add the comment or set phoSoapClientHelper to 0.

See Also

Building Client Side Web Services


Handling XML Data

Normally, complex data is passed back and forth as structs and arrays. When structs and arrays are used, you never have to deal with the actual underlying XML data. In some cases, the data will be passed of returned as XML. This occurs when either 1) the web service specifically passes the data as XML, or 2) the data passed could not be reduced to a single fundamental native data-type (e.g. string), struct or array. When such data is used, the data is passed and returned as an XML object.

Most of the time you will never have to deal directly with XML data in web-services. If you do, this section explains how it is done.

If you are working with XML data most often you will be dealing with return data. In such a case, the data is returned as handle to an XML object. You will need to parse this data, use it as needed and then destroy the XML object.

Parsing this kind of data is surprisingly simple, if you know how to do it. To work successfully with the data you need to:

  1. Know how the XML document data is structured.

  2. Know the full expanded-name of each element. An expanded name consists of the NameSpaceURI and the BaseName

  3. Know what methods to use to get at the data.

See Also

How to Parse XML Data

Multiple Namespaces in an XML Document

The Document Data Structure

You can see what the data looks like (solving 1 and 2 above) by looking at the returned data. Use the Web Client Helper View to see this data (Add use "WebClientHelper.vw" to the top of your program and enter "Set phoSoapClientHelper to oClientWSHelper" inside your client object).

If should be noted that the proper way to know a document’s structure is to look at it’s schema definition (located in the WSDL). Reading through a schema definition can be daunting. Most of the time, you can just look at the document and see the data structure.

BaseName and NameSpaceURI

The BaseName is the name within the element tags. If the element contains a prefix just look at the name to the right of the “:”. An element prefix consists of a name followed by a colon, which is followed by the BaseName (<m:MyElement>). If no prefix exists, the BaseName is the entire element name.

You can find the NameSpaceURI one of several ways. We will start by discussing a method that will work most of the time. The NameSpaceURI is a name that usually looks like a web address like http://www.dataaccess.com/Test/CustomerList. (It’s probably not a real address - URLs are used because it provides a good way to create a unique name.) In most cases, the return data will all have the same NameSpaceURI. If you look at the client helper view, you will see that it displays this information (look for “Document NameSpaceURI =”xxxx”). Most of the time, you can use this name. You can do this if all of the elements have the same prefix (e.g., all elements start with x) or if none of the elements have a prefix.

In some cases the data will be have multiple namespaces. In such a case, you need to review the section titled " Multiple namespaces in an XML document ".

For now let's assume you've got single namespace data.

The XML Parsing Methods

The XML classes have a number of namespace aware messages that make it easy to work with namespaces. You want to use these messages. There is a tendency for developers to attempt to ignore the namespaces and to attempt to work with an element’s prefix and BaseName. Avoid this tendency, as it tends to create solutions that seem to work and then proceed to get very messy. Methods are available that make it very easy to parse the documents in the proper manner.

The main methods you will use to parse you return data will be:

Get DocumentElement

This returns the root element of your document.

Get DocumentElement of hoXML to hoRoot

You always work from this root. This first thing to do with any XML Document is to get the root element. All of your parsing will use this root object as your starting point.

Get FirstChild

This returns the first child node of an element

Get FirstChild of hoRoot to hoNode

Get NextNode

This replaces the current XML node with the next node (i.e., its sibling node).

Get NextNode of hoNode to hoNode

Get ChildElementNS

This returns the first child node that matches an expanded name (NameSpaceURI and basename).

Get ChildElementNS of hoRoot sNameSpace "Customer" to hoCust

Get NextElementNS

This replaces the current XML node with the next node that matches an expanded name.

Get NextElementNS of hoCust sNameSpace "Customer" to hoCust

Get ChildElementValueNS

This returns an element's value for an expanded name.

Get ChildElementValueNS of hoCust sNameSpace "name" to sName

Send Destroy

This destroys XML nodes when you are done with them.

Send Destroy of hoXML

If you know the structure of your XML document and you know an element’s BaseName and NameSpaceURI you can use these few messages to handle most of your parsing.

See Also

Publishing and Using Web Services


How to Parse XML Data

All of these examples are applied to data that resides in a single workspace. This will be the most common type of data.

Example 1:

Assume you have the following returned XML document:

<Customer xmlns="http://www.dataaccess.com/Test/CustomerList">

<Name>3A Software</Name>

<Number>13</Number>

<State>CA</State>

</Customer>

If you look at the client view helper in the "Data" window you will see the line:

Document NameSpaceURI = http://www.dataaccess.com/Test/CustomerList

That's your NameSpaceURI. We'd parse this as follows:

Get wsCustInfo of hoMyClient "13" to hoXML

// if no data, we've had an error that has been reported.

If hoXML begin

Move "http://www.dataaccess.com/Test/CustomerList" to sNS // the namespace

Get DocumentElement of hoXML to hoRoot

Get ChildElementValueNS of hoRoot sNS "Name" to sName

Get ChildElementValueNS of hoRoot sNS "Number" to sNumber

Get ChildElementValueNS of hoRoot sNS "State" to sState

Send destroy of hoXML

end

Example 2:

Assume you have the more complex data:

<CustomerList xmlns="http://www.dataaccess.com/Test/CustomerList">

<Customer>

<Name>3A Software</Name>

<Number>13</Number>

<State>CA</State>

</Customer>

<Customer>

<Name>Ace Manufacturers, Inc.</Name>

<Number>4</Number>

<State>IL</State>

</Customer>

<Customer>

<Name>All Canada Brewing Company</Name>

<Number>24</Number>

<State>CA</State>

</Customer>

</CustomerList>

Find the NameSpaceURI using the same technique as example 1 and parse this as follows:

Get wsAllCust of hoMyClient to hoXML

// if no data, we've had an error that has been reported.

If hoXML begin

Move "http://www.dataaccess.com/Test/CustomerList" to sNS // the namespace

Get DocumentElement of hoXML to hoRoot // this is CusomterList

Get ChildElementNS of hoRoot sNS "Customer" to hoCust

While hoCust

Get ChildElementValueNS of hoCust sNS "Name" to sName

Get ChildElementValueNS of hoCust sNS "Number" to sNumber

Get ChildElementValueNS of hoCust sNS "State" to sState

Send DoThisCustomer sName sNumber sState

Get NextElementNS of hoCust sNS "Customer" to hoCust

end

Send destroy of hoXML

end

You could also have used FirstChild and NextNode as follows:

Get wsAllCust of hoMyClient to hoXML

// if no data, we've had an error that has been reported.

If hoXML begin

Move "http://www.dataaccess.com/Test/CustomerList" to sNS // the namespace

Get DocumentElement of hoXML to hoRoot

Get FirstChild of hoRoot to hoCust

While hoCust

Get ChildElementValueNS of hoCust sNS "Name" to sName

Get ChildElementValueNS of hoCust sNS "Number" to sNumber

Get ChildElementValueNS of hoCust sNS "State" to sState

Send DoThisCustomer sName sNumber sState

Get NextNode of hoCust to hoCust

end

Send destroy of hoXML

end

Example 3:

Sometimes your element names might use prefixes (e.g., <m:name>). If the namespace is defined with the same prefix (e.g. xmlns:m="SomeUrl") and all of the elements are using this prefix, you follow the same instructions as above. For example:

<ns:Customer xmlns:ns="http://www.dataaccess.com/Test/CustomerList">

<ns:Name>3A Software</ns:Name>

<ns:Number>13</ns:Number>

<ns:State>CA</ns:State>

</ns:Customer>

You'd parse this in the exact same manner as example 1. In fact, these two documents in example 1 and 3 are identical.

Example 4:

Assume you have the following returned XML document:

<Customer>

<Name>3A Software</Name>

<Number>13</Number>

<State>CA</State>

</Customer>

This does not appear to have a namespace. It doesn’t. If you look at the client view helper in the "Data" window you will see the line:

Document NameSpaceURI = ""

When there is no namespace defined, you are working in the global namespace which is identified as "". Therefore, use "" as your NameSpaceURI. We'd parse this as follows:

Get wsCustInfo of hoMyClient "13" to hoXML

// if no data, we've had an error that has been reported.

If hoXML begin

Move "" to sNS // empty means the global namespace

Get DocumentElement of hoXML to hoRoot

Get ChildElementValueNS of hoRoot sNS "Name" to sName

Get ChildElementValueNS of hoRoot sNS "Number" to sNumber

Get ChildElementValueNS of hoRoot sNS "State" to sState

Send destroy of hoXML

end

See Also

Handling XML Data


Multiple Namespaces in an XML Document

In some cases, your data might contain more than one NameSpaceURI. This can be easily handled. The only difference is that you need to know how namespaces are defined and how they are associated with elements.

When you parse data, you often search for elements by name. To do this, you need to know the expanded-name of elements. The expanded name consists of the element's NameSpaceURI and the element's BaseName. When you search, you will pass the expanded name as two parameters - NameSpaceURI and BaseName.

So how do you know what the NameSpaceURI and Basename values are? There are several ways to do this, but a good approach is to look at the XML data returned and figure it out. Let's provide some examples

Elements with Prefixes

In some cases, you will have a prefix in the element. Assume we have the following:

<m:Orders xmlns:m="http://DataAccess.com/webservices/">

<m:Order>

<m:OrderNo>1</m:OrderNo>

<m:CustomerNo>99</m:CustomerNo>

:

</m:Order>

</m:Orders>

To figure out what the BaseNames are, just ignore all of the prefixes (m:). In this case we've got four elements, Orders, Order, OrderNo and CustomerNo. Since the prefix for all of these elements is “m:” we need to find the NameSpaceURI associated with this prefix. Starting at element, search for an attribute xmlns:m and use its value. In this case, that would be "http://DataAccess.com/webservices/". The expanded names of these elements are:

http://DataAccess.com/webservices/ + Orders

http://DataAccess.com/webservices/ + Order

http://DataAccess.com/webservices/ + OrderNo

http://DataAccess.com/webservices/ + CustomerNo

You'd code this as follows:

Get DocumentElement of hoXML to hoRoot

Get ChildElementNS of hoRoot "http://DataAccess.com/webservices/" "Order" to hoOrder

Get ChildElementValueNs of hoOrder "http://DataAccess.com/webservices/" "OrderNo" to sOrderNo

Get ChildElementValueNs of hoOrder "http://DataAccess.com/webservices/" "CustomerNo" to sCustomerNo

Send destroy of hoOrder

You'd be more likely to code this as follows:

Move "http://DataAccess.com/webservices/" to sNS

Get DocumentElement of hoXML to hoRoot

Get ChildElementNS of hoRoot sNS "Order" to hoOrder

Get ChildElementValueNs of hoOrder sNS "OrderNo" to sOrderNo

Get ChildElementValueNs of hoOrder sNS "CustomerNo" to sCustomerNo

Send destroy of hoOrder

Elements without Prefixes

In some cases, you will not have a prefix in the element. When that happens you are using a default namespace identified with an attribute called "xmlns=" or, if there is no attribute, the global namespace is used (""). If you find the “xmlns=” attribute, you have an element with a default-namespace. If you don't find the attribute, you have an element in the global workspace.

Elements with Default-Namespaces

Assume we have the following:

<Orders xmlns="http://DataAccess.com/webservices/">

<Order>

<OrderNo>1</OrderNo>

<CustomerNo>99</CustomerNo>

:

</Order>

</Orders>

Since there are no prefixes, the BaseNames are the element names – Orders, Order, OrderNo and CustomerNo. To figure out what the NameSpaceURI is, search for an attribute “xmlns=” and use its value. In this case, that would be

“http://DataAccess.com/webservices/". The expanded names of these elements are:

http://DataAccess.com/webservices/ + Orders

http://DataAccess.com/webservices/ + Order

http://DataAccess.com/webservices/ + OrderNo

http://DataAccess.com/webservices/ + CustomerNo

You'd code this as follows:

Move "http://DataAccess.com/webservices/" to sNS

Get DocumentElement of hoXML to hoRoot

Get ChildElementNS of hoRoot sNS "Order" to hoOrder

Get ChildElementValueNs of hoOrder sNS "OrderNo" to sOrderNo

Get ChildElementValueNs of hoOrder sNS "CustomerNo" to sCustomerNo

Send destroy of hoOrder

The above two examples represent the same XML document data!

Elements with no Default-Namespaces (Global Namespace)

Assume we have the following:

<Orders>

<Order>

<OrderNo>1</OrderNo>

<CustomerNo>99</CustomerNo>

:

</Order>

</Orders>

Since there are no prefixes, the BaseNames are the element names - Orders, Order, OrderNo and CustomerNo. To figure out what the NameSpaceURI is, search for an attribute “xmlns=” and use its value. Since this can't be found, the namespace is global. ("") The expanded names of these elements are:

"" + Orders

"" + Order

"" + OrderNo

"" + CustomerNo

You'd code this as follows:

Move "" to sNS

Get DocumentElement of hoXML to hoRoot

Get ChildElementNS of hoRoot sNS "Order" to hoOrder

Get ChildElementValueNs of hoOrder sNS "OrderNo" to sOrderNo

Get ChildElementValueNs of hoOrder sNS "CustomerNo" to sCustomerNo

Send destroy of hoOrder

Documents with multiple Namespaces

A document may contain a mix of prefixes and namespaces. When this happens, you apply the same rules as above on an element-by-element basis.

  • For each element, you check to see if it has a prefix.

  • If it does have a prefix you search for the attribute (xmlns:ns=) that defines the namespace for that prefix.

  • If it does not have a prefix, you look for an attribute that defines a default namespace (xmlns=). If no namespace is found the NameSpace is global

  • Parse the element using the NameSpaceURI and the BaseName.

Do this for every element

For example:

<Orders xmlns="http://DataAccess.com/webservices/"

xmlns:m="http://DataAccess.com/Customers/">

<Order>

<OrderNo>1</OrderNo>

<m:Customer>

<m:CustomerNo>99</m:CustomerNo>

<m:CustomerName>Fred</m:CustomerName>

</m:Customer>

</Order>

</Orders>

We have the following elements with the following expanded-names

http://DataAccess.com/webservices/ + Orders

http://DataAccess.com/webservices/ + Order

http://DataAccess.com/webservices/ + OrderNo

http://DataAccess.com/Customers/ + Customer

http://DataAccess.com/Customers/ + CustomerNo

http://DataAccess.com/Customers/ + CustomerName

You'd code this as follows:

Move "http://DataAccess.com/webservices/" to sNS1

Move "http://DataAccess.com/Customers/" to sNS2

Get DocumentElement of hoXML to hoRoot

Get ChildElementNs of hoRoot sNS1 "Order" to hoOrder

Get ChildElementValueNs of hoOrder sNS1 "OrderNo" to sOrderNo

Get ChildElementNs of hoOrder sNS2 "Customer" to hoCust

Get ChildElementValueNs of hoCust sNS2 "CustomerNo" to sCustomerNo

Get ChildElementValueNs of hoCust sNS2 "CustomerName" to sName

Send destroy of hoCust

Send destroy of hoOrder

Consider the following two XML documents. These represent the same data. Since the documents are the same, the code example shown above will be applied to all of these documents.

In this case, we apply prefixes to all elements:

<Orders xmlns:x="http://DataAccess.com/webservices/"

xmlns:m="http://DataAccess.com/Customers/">

<x:Order>

<x:OrderNo>1</x:OrderNo>

<m:Customer>

<m:CustomerNo>99</m:CustomerNo>

<m:CustomerName>Fred</m:CustomerName>

</m:Customer>

</x:Order>

</x:Orders>

In this case, we reverse the prefix names.

<m:Orders xmlns:m="http://DataAccess.com/webservices/"

xmlns="http://DataAccess.com/Customers/">

<m:Order>

<m:OrderNo>1</m:OrderNo>

<Customer>

<CustomerNo>99</CustomerNo>

<CustomerName>Fred</CustomerName>

</Customer>

</m:Order>

</m:Orders>

This final example mixes three namespaces. This document has three elements with the same BaseName (State) and it mixes namespaces throughout the document. You will never see a real document like this. In a situation like this you do not need to try to understand why the document was created this way. Whoever designed the service and the schema made the decision. All you need to worry about is using the service.

<Orders xmlns="http://DataAccess.com/webservices/"

xmlns:m="http://DataAccess.com/webservicesOrders/"

xmlns:x="">

<x:Order>

<OrderNo>1</OrderNo>

<m:Customer>

<m:CustomerNo>99</m:CustomerNo>

<x:State>CA</x:State>

<m:State>Angry</m:State>

<State>Yes</State>

</m:Customer>

</x:Order>

</Orders>

We have the following elements with the following expanded-names

http://DataAccess.com/webservices/ + Orders

"" + Order

http://DataAccess.com/webservices/ + OrderNo

http://DataAccess.com/webservicesOrders/ + Customer

http://DataAccess.com/webservicesOrders/ + CustomerNo

"" + State

http://DataAccess.com/webservicesOrders/ + State

http://DataAccess.com/webservices/ + State

You'd code this as follows:

Move "http://DataAccess.com/webservices/" to sNS1

Move "http://DataAccess.com/webservicesOrders/" to sNS2

Move "" to sNS3

Get DocumentElement of hoXML to hoRoot

Get ChildElementNs of hoRoot sNS3 "Order" to hoOrder

Get ChildElementValueNs of hoOrder sNS1 "OrderNo" to sOrderNo ---> 1

Get ChildElementNs of hoOrder sNS2 "Customer" to hoCust

Get ChildElementValueNs of hoCust sNS2 "CustomerNo" to sCustomerNo ---> 99

Get ChildElementValueNs of hoCust sNS3 "State" to sRegion ---> CA

Get ChildElementValueNs of hoCust sNS2 "State" to sStateOfMind ---> Angry

Get ChildElementValueNs of hoCust sNS1 "State" to sMaintainsState ---> Yes

Send destroy of hoCust

Send destroy of hoOrder

If this makes sense, you know how to parse xml documents with namespaces.

See Also

Handling XML Data