Handling complex data types

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

This section describes both categories.

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
binary
xsd:base64Binary
date
xsd:dateTime
void (operation returns nothing)

struct*
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. You have to perform some processing on the data in order to access it as a structure. 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, you create a ColdFusion structure, initialize six fields of the structure that correspond to the six elements of Employee, 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/echosimple.asmx?wsdl");
  ws.echoStruct(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, you have to inspect the WSDL file for the web service to determine the layout of the complex type. This 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 the dot notation in the same way 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, you have to inspect the WSDL file for the web service. The WSDL file defines the API to the web service and will provide 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 needs to 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 very 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="Map">
  <sequence>
    <element name="item" minOccurs="0" maxOccurs="unbounded">
      <complexType>
        <all>
          <element name="key" type="xsd:anyType" />
          <element name="value" type="xsd:anyType" />
        </all>
      </complexType>
    </element>
  </sequence>
</complexType>

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

If you register the component in Dreamweaver MX, it appears in the Application panel as the following figure shows:

The echostruct web service shown in Dreamweaver MX

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. For example, if you have a structure containing the field A.B.C, that field is represented as the following figure shows:

The WSDL mapping of a ColdFusion structure.

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
2-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> 

Comments