Handling complex data types

When dealing with web services, handling complex types falls into the following categories:

  • Mapping the data types of a web service to consume to ColdFusion data types

  • Understanding how clients reference your ColdFusion data types when you publish a web service

Consuming web services that use complex data types

The following table shows how WSDL data types are converted to ColdFusion data types:

ColdFusion data type

WSDL data type

numeric

SOAP-ENC:double

Boolean

SOAP-ENC:boolean

string

SOAP-ENC:string

array

SOAP-ENC:Array

numeric

SOAP-ENC:float

binary

xsd:base64Binary

date

xsd:dateTime

void (operation returns nothing)

 

structure

complex type

This table shows that complex data types map to ColdFusion structures. ColdFusion structures offer a flexible way to represent data. You can create structures that contain single-dimension arrays, multi-dimensional arrays, and other structures.

The ColdFusion mapping of complex types to structures is not automatic. Accessing the data as a structure requires some processing of the data. The next sections describe how to pass complex types to web services, and how to handle complex types returned from web services.

Passing input parameters to web services as complex types

A web service can take a complex data type as input. In this situation, you can construct a ColdFusion structure that models the complex data type, then pass the structure to the web service.

For example, the following excerpt from a WSDL file shows the definition of a complex type named Employee:

<s:complexType name="Employee">  
    <s:sequence>  
      <s:element minOccurs="1" maxOccurs="1" name="fname" type="s:string" />  
      <s:element minOccurs="1" maxOccurs="1" name="lname" type="s:string" />  
      <s:element minOccurs="1" maxOccurs="1" name="active" type="s:boolean" />  
      <s:element minOccurs="1" maxOccurs="1" name="age" type="s:int" />  
      <s:element minOccurs="1" maxOccurs="1" name="hiredate" type="s:dateTime" />  
      <s:element minOccurs="1" maxOccurs="1" name="number" type="s:double" />  
    </s:sequence>  
</s:complexType>

The Employee data type definition includes six elements, the data type of each element, and the name of each element.

Another excerpt from the WSDL file shows a message definition using the Employee data type. This message defines an input parameter, as the following code shows:

<message name="updateEmployeeInfoSoapIn">  
    <part name="thestruct" type="s0:Employee" />  
</message>

A third excerpt from the WSDL file shows the definition of an operation, named updateEmployeeInfo, possibly one that updates the employee database with the employee information. This operation takes as input a parameter of type Employee, as the following code shows:

<operation name="updateEmployeeInfo">  
    <input message="s0:updateEmployeeInfoSoapIn" />  
</operation>

To call the updateEmployeeInfo operation, create a ColdFusion structure, initialize six fields of the structure that correspond to the six elements of Employee, and then call the operation, as the following code shows:

<!--- Create a structure using CFScript, then call the web service. ---> 
<cfscript> 
    stUser = structNew(); 
    stUser.active = TRUE; 
    stUser.fname = "John"; 
    stUser.lname = "Smith"; 
    stUser.age = 23; 
    stUser.hiredate = createDate(2002,02,22); 
    stUser.number = 123.321; 
 
    ws = createObject("webservice", "http://somehost/EmployeeInfo.asmx?wsdl"); 
    ws.updateEmployeeInfo(stUser); 
</cfscript> 

You can use structures for passing input parameters as complex types in many situations. However, to build a structure to model a complex type, inspect the WSDL file for the web service to determine the layout of the complex type. This process can take some practice.

Handling return values as complex types

When a web service returns a complex type, you can write that returned value directly to a ColdFusion variable.

The previous section used a complex data type named Employee to define an input parameter to an operation. A WSDL file can also define a return value using the Employee type, as the following code shows:

<message name="updateEmployeeInfoSoapOut">  
    <part name="updateEmployeeInfoResult" type="s0:Employee" />  
</message> 
<operation name="updateEmployeeInfo">  
    <input message="s0:updateEmployeeInfoSoapIn" />  
    <output message="s0:updateEmployeeInfoSoapOut" />  
</operation>

In this example, the operation updateEmployeeInfo takes a complex type as input and returns a complex type as output. To handle the input parameter, you create a structure. To handle the returned value, you write it to a ColdFusion variable, as the following example shows:

<!--- Create a structure using CFScript, then call the web service. ---> 
<!--- Write the returned value to a ColdFusion variable. ---> 
<cfscript> 
    stUser = structNew(); 
    stUser.active = TRUE; 
    stUser.fname = "John"; 
    stUser.lname = "Smith"; 
    stUser.age = 23; 
    stUser.hiredate = createDate(2002,02,22); 
    stUser.number = 123.321; 
 
    ws = createObject("webservice", "http://somehost/echosimple.asmx?wsdl"); 
    myReturnVar = ws.echoStruct(stUser); 
 
</cfscript>  
 
<!--- Output the returned values. ---> 
<cfoutput> 
    <br> 
    <br>Name of employee is: #myReturnVar.fname##myReturnVar.lname# 
    <br>Active status: #myReturnVar.active# 
    <br>Age:#myReturnVar.age# 
    <br>Hire Date: #myReturnVar.hiredate# 
    <br>Favorite Number: #myReturnVar.number#  
</cfoutput>

You access elements of the variable myReturnVar using dot notation in the same way that you access structure fields. If a complex type has nested elements, in the way a structure can have multiple levels of nested fields, you use dot notation to access the nested elements, as in a.b.c.d, to whatever nesting level is necessary.

However, the variable myReturnVar is not a ColdFusion structure. It is a container for the complex type, but has none of the attributes of a ColdFusion structure. Calling the ColdFusion function isStruct on the variable returns False.

You can copy the contents of the variable to a ColdFusion structure, as the following example shows:

<cfscript> 
... 
    ws = createObject("webservice", "http://somehost/echosimple.asmx?wsdl"); 
    myReturnVar = ws.echoStruct(stUser); 
 
    realStruct = structNew(); 
    realStruct.active = #myReturnVar.active#; 
    realStruct.fname = "#myReturnVar.fname#"; 
    realStruct.lname = "#myReturnVar.lname#"; 
    realStruct.age = #myReturnVar.age#; 
    realStruct.hiredate = #myReturnVar.hiredate#; 
    realStruct.number = #myReturnVar.number#; 
 
</cfscript> 

Calling IsStruct on realStruct returns True and you can use all ColdFusion structure functions to process it.

This example shows that ColdFusion variables and structures are useful for handling complex types returned from web services. To understand how to access the elements of a complex type written to a ColdFusion variable, inspect the WSDL file for the web service. The WSDL file defines the API to the web service and provides you with the information necessary to handle data returned from it.

Publishing web services that use complex data types

The two ColdFusion data types that do not map exactly to WSDL data types are struct and query. When you publish a ColdFusion web service that uses parameters of type struct or query, the consuming application must be able to handle the data.

Note: If the consumer of a ColdFusion web service is another ColdFusion application, you do not have to perform any special processing. ColdFusion correctly maps struct and query data types in the web service publisher with the consumer. For more information, see Consuming ColdFusion web services.

Publishing structures

A ColdFusion structure can hold an unlimited number of key-value pairs where the values can be of any ColdFusion data type. While it is a useful and powerful way to represent data, it cannot be directly mapped to any XML data types defined in the SOAP 1.1 encoding and XML Schema specification. Therefore, ColdFusion structures are treated as a custom type and the complex type XML schema in WSDL looks like the following:

<complexType name="mapItem"> 
     <sequence> 
       <element name="key" nillable="true" type="xsd:anyType"/> 
       <element name="value" nillable="true" type="xsd:anyType"/> 
     </sequence> 
</complexType> 
<complexType name="Map"> 
     <sequence> 
       <element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/> 
     </sequence> 
</complexType>

This complex type defines a representation of a structure, where the structure keys and values can be any type.

In the WSDL mapping of a ColdFusion structure, each key-value pair in the structure points to the next element in the structure except for the final field, which contains a value. Use dot notation to access the key-value pairs.

Publishing queries

ColdFusion publishes query data types as the WSDL type QueryBean. The QueryBean data type contains two elements, as the following excerpt from a WSDL file shows:

<complexType name="QueryBean">  
    <all>  
        <element name="data" nillable="true" type="intf:ArrayOf_SOAP-ENC_Array" />  
        <element name="ColumnList" nillable="true" 
    type="intf:ArrayOf_SOAP-ENC_string" />  
    </all>  
</complexType> 

The following table describes the elements of QueryBean:

Element name

Description

ColumnList

String array that contains column names

data

Two-dimensional array that contains query data

The WSDL file for a QueryBean defines these elements as follows:

<complexType name="ArrayOf_SOAP-ENC_Array">  
    <complexContent>  
        <restriction base="SOAP-ENC:Array">  
            <attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="SOAP-ENC:Array[]" />  
        </restriction>  
    </complexContent>  
</complexType>  
<complexType name="ArrayOf_SOAP-ENC_string">  
    <complexContent>  
    <restriction base="SOAP-ENC:Array">  
        <attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="xsd:string[]" />  
    </restriction>  
    </complexContent>  
</complexType>