Ask a Question related to Coldfusion - Advanced Techniques, Design and Development.
-
afrinl #1
Re: Tricky SOAP input problem; need help with cfinvokesyntax
Notes on Interfacing CFMX to External Web Services Requiring
Complex-Within-Complex XML Documents as Input Authors: Doug James
(jamesd@musc.edu) Larry Afrin, MD (afrinl@musc.edu) Hollings Cancer Center
Medical University of South Carolina March 31, 2005 <cfacknowledgement> The
authors would like to acknowledge Macromedia's Tom Jordahl (who we understand
is sort of the principal developer and 'guru' of ColdFusion's web services
functionality) both for his assistance in helping them understand how
ColdFusion handles certain complex web service interactions and for his
critical review of the following document. </cfacknowledgement>
<cfdisclaimer> While the authors have tried to ensure the accuracy and utility
of the information below, they offer the following information with no
warranties whatsoever and hereby explicitly state that their employer has had
absolutely nothing to do with the development of this document and therefore
also bears no liabilities with regard to how the information presented here may
be used. The authors are also quite sure that despite Tom Jordahl's review of
this document, Macromedia takes no responsibility for this information, either.
By their posting of this information, the authors are not offering themselves
as support resources for other developers wrestling with the problems addressed
herein. Requests for assistance in this area that are communicated to the
authors may or may not be acknowledged or answered, solely at the authors'
whim. After all, we do have to attend first to our day jobs (which often spill
over into our night jobs, too.) ;-) </cfdisclaimer>
================================================== ===== CFMX is able to
communicate with web services hosted in arbitrary computing environments as
long as the SOAP standards are followed. The SOAP standards require that all
input arguments to a web service be passed as XML documents. The expected
format of the XML document for any given input argument is defined either
directly in the service's WSDL (Web Services Description Language) document, or
by reference in that WSDL document to another data element definition document.
Before proceeding further to discuss how CFMX handles 'complex'-type web
service input arguments, it is helpful to review how CFMX handles a <cfinvoke>
(or equivalent) request in general. CFMX first retrieves the target service's
WSDL, then runs this WSDL through the WSDL2Java tool (see below for more
information), which outputs Java code defining Java-based classes equivalent to
the XML data structures defined in the WSDL. This Java code is then compiled.
The input arguments provided to <cfinvoke> are then mapped to the Java types
generated by the compilation, and finally the Java stub functions for those
types are called. In this fashion, CFMX *automatically* converts input values
referenced in <cfinvoke> or <cfinvokeargument> tags to XML documents of the
appropriate formats based on input argument format information provided in the
service's WSDL. The burden on the coder, of course, is to ensure the input
values are structured in accordance with what CFMX expects to find based on the
translation by WSDL2Java from an XML-based data structure to a Java-based data
structure. A similar process is followed to handle the service's return value
and other output arguments. This process is quite straightforward for 'simple'
type input arguments, such as simple strings or numeric values. Because
ColdFusion variables, strictly speaking, are untyped, CFMX automatically
converts simple input ColdFusion variables to the equivalent string-based
simple XML structures. However, some web service input arguments are XML
documents of 'complex' type. As briefly described in the ColdFusion MX 7
documentation at:
[url]http://livedocs.macromedia.com/coldfusion/7/htmldocs/00001554.htm[/url] for
complex-type arguments, CFMX expects to find a ColdFusion structure provided as
the value for the input argument. Unfortunately, the ColdFusion MX
documentation only provides clear examples of how to compose a ColdFusion
structure that corresponds merely to a relatively simple form of a 'complex'
XML document in which the child elements of an outer 'complex' parent element
are simple scalar values, as illustrated in Example 1: ---------Example
1:------------------------------------ WSDL snippet: <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='age' type='s:int' /> </s:sequence> </s:complexType> Sample XML
document: <Employee> <fname>John</fname> <lname>Smith</fname>
<age>25</age> </Employee> CFML snippet: <!--- Create a structure using
CFScript, then call the web service. ---> <cfscript> stUser = structNew();
stUser.fname = 'John'; stUser.lname = 'Smith'; stUser.age = 23; ws =
createObject('webservice', 'http://somehost/echosimple.asmx?wsdl');
ws.echoStruct(stUser); </cfscript>
------------------------------------------------------- While the above is
helpful for 'simple' complex-type input arguments, the ColdFusion MX
documentation provides no examples of how to compose a ColdFusion structure
that corresponds to a more complex form of a complex-type XML document in which
the child elements of an outer 'complex' parent element are themselves
'complex' parent elements (so-called 'complex-within-complex' XML documents),
as illustrated in Example 2: ---------Example
2:------------------------------------ WSDL snippet: <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='0'
maxOccurs='unbounded' name='nickname' type='s:nickname' /> <s:element
minOccurs='1' maxOccurs='1' name='age' type='s:int' /> <s:element
ref='s:address' minOccurs='0' maxOccurs='unbounded' name='address' />
</s:sequence> <xsd:attribute name='employeeGender' type='string'
use='required'/> </s:complexType> <s:complexType name='nickname'>
<s:simpleContent> <s:extension base='string' /> </s:simpleContent>
</s:complexType> <s:complexType name='address'> <s:sequence>
<s:element minOccurs='1' maxOccurs='1' name='street' type='s:string' />
<s:element minOccurs='1' maxOccurs='1' name='street' type='s:string' />
<s:element minOccurs='1' maxOccurs='1' name='state' type='s:state' />
<s:element minOccurs='1' maxOccurs='1' name='zip' type='s:zip' />
</s:sequence> <xsd:attribute name='addressType' type='string'
use='required'/> </s:complexType> Sample XML document: <Employee
employeeGender='Male'> <fname>John</fname> <lname>Smith</fname>
<nickname>Jack</nickname> <nickname>Johnny</nickname> <age>25</age>
<address addressType='Home'> <street>25 Main Street</street>
<city>Townville</street> <state>Anystate</state> <zip>99999</zip>
</address> </Employee> CFML snippet: <!--- Create a structure using
CFScript, then call the web service. ---> <cfscript> stUser = structNew();
stUser.fname = 'John'; stUser.lname = 'Smith'; stUser.age = 23; <!---
If .x corresponds to *element* <x>, then what syntax is used to specify an
*attribute*? How should employeeGender get set up in this struct?
Read on to find out. ---> <!--- And what about the *two*
nicknames? stUser.nickname = ... clearly won't work. Read on to find
out how this is handled. --->
<!--- And what about <address>? Does that get coded simply as stUser.address =
structNew(), stUser.address.street = '25 Main Street', etc. etc.?????
The answer is 'No.' Read on to find out more.
---> ws = createObject('webservice',
'http://somehost/echosimple.asmx?wsdl'); ws.echoStruct(stUser); </cfscript>
------------------------------------------------------- There are just a few
key (pardon the pun) principles you need to understand in order to determine
how to compose a CF structure that CFMX will map to the properly formatted XML
document needed as an input argument to an arbitrary web service: (1)
Principle #1: Any given key in a CF structure will be mapped by CFMX into
*either* an element name *or* an attribute name depending on what role the WSDL
says that particular name should play at that level in the document. In other
words, you do not need to differentiate between attributes and elements in the
CFML structure you create; ColdFusion will automatically handle for you the
proper mapping of each key into either an attribute or element as required by
the WSDL. Following along with Example 2 above, then, stUser.age will get
translated into an <age> child *element* within the <Employee> parent element,
and stUser.employeeGender will get translated as the employeeGender *attribute*
within the <Employee> element. (2) Elements in a WSDL that can occur more than
once (cf. the 'address' element in Example 2 above) are represented in the CF
struct as an array. OK, but an array of what? Well, it depends on how the
WSDL defines the subelements. Again, following along with Example 2 above,
<address> would be coded into the stUser structure as follows:
stUser.address = arrayNew(1); stUser.address[1] = structNew();
stUser.address[1].street = '25 Main Street'; stUser.address[1].city =
'Townville'; stUser.address[1].state = 'Anystate'; stUser.address[1].zip
= '99999'; stUser.address[1].addressType = 'Home'; and the nicknames would
be coded a
afrinl Guest
-
A tricky query problem
what i am trying to do is 1. let a user decide which language they want 2. pull the apropriate information fom a few different tables project... -
Tricky problem with WebControl vs. Panel
I have built a class derived from WebControl, and added somespecific functionality to it..Then I built a set of web controlsbased on that... -
Tricky problem with classes!
Problem: I try to store data in a objects field and read it out again. Sounds easy, yeah. But its a bit tricky here.... ;-) This is the class... -
tricky disable button problem
Ok, I need to know a little actionscript and hope you will be able to help - I have always found replies here. I have my main movie with home,... -
Problem of using apache soap to consume WSE 2.0 soap attachment
I developed a web service at .NET with WSE 2.0 attachming soap attachment with soap response, and I can write a .NET client app to consume it. ... -
Tom Jordahl #2
Re: Tricky SOAP input problem; need help with cfinvoke syntax
This is great stuff and we plan on publishing a tech note with this
information as well.
Thanks for Larry and Doug for putting this document together.
--
Tom Jordahl
Macromedia Server Development
Tom Jordahl Guest
-
afrinl #3
Re: Tricky SOAP input problem; need help with cfinvokesyntax
Unfortunately, a good bit of the original formatting of the answer I posted was
not preserved upon posting here in the forum. An alternative view with
improved formatting is available here:
[url]http://hcc.musc.edu/research/shared_resources/xml_complex_types_to_cf_structure_[/url]
notes.cfm I hope this helps. -- LBA
afrinl Guest
-
Mike Greider #4
Re: Tricky SOAP input problem; need help with cfinvokesyntax
Excellent post. Thanks for the info.
Mike Greider Guest



Reply With Quote

