Copy link to clipboard
Copied
Ok I have a web service that I'm trying to consume in CF9. I'm able to hit the wsdl with SOAPUI and see the results. The results come back in XML format. It basically shows a list of rooms we use as meetings and show the times they are reserved. Here's the CF code I've written for it:
<cfinvoke
webservice="http://dwc-dreiman-w7e/WSExchangeMeetingRooms/exchange.asmx?WSDL"
method="FindResourceDetailForDay"
returnvariable="FindResourceDetailForDayResponse">
<cfinvokeargument name="c" value="Deerwood">
<cfinvokeargument name="d" value="">
</cfinvoke>
<cfoutput>Test value returns #FindResourceDetailForDayResponse#</cfoutput>
However that code returns this: Test value returns org.tempuri.FindResourceDetailForDayResponseFindResourceDetailForDayResult@13d9efc
The information that SoapUI returns in XML format is this:
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<calendar xmlns="">
<Dwc-Room-02 diffgr:id="Dwc-Room-021" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 11:00:00 AM</StartTime>
<EndTime>10/6/2010 12:00:00 PM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Construction Meeting</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-02>
<Dwc-Room-01 diffgr:id="Dwc-Room-011" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 9:00:00 AM</StartTime>
<EndTime>10/6/2010 11:00:00 AM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Leadership Meeting</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-01>
<Dwc-Room-01 diffgr:id="Dwc-Room-012" msdata:rowOrder="1" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 12:00:00 PM</StartTime>
<EndTime>10/6/2010 2:00:00 PM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Strategic Conversation</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-01>
<Dwc-Room-01 diffgr:id="Dwc-Room-013" msdata:rowOrder="2" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 2:00:00 PM</StartTime>
<EndTime>10/6/2010 3:00:00 PM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Board Meeting</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-01>
</calendar>
</diffgr:diffgram>
How do I go about accessing the information within the parent/child nodes of the XML? This is my first time working with complex webservices in Coldfusion.
SOAP means you have to send a SOAP XML to the web service. Do something like:
<!--- WSDL --->
<cfset wsdl_url="http://dwc-dreiman-w7e/WSExchangeMeetingRooms/exchange.asmx?WSDL">
<cftry>
<!--- Compose SOAP message to send to Web Service--->
<cfsavecontent variable="soap"><?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-ins
Copy link to clipboard
Copied
Rather then <cfoutput>Test value returns #FindResourceDetailForDayResponse#</cfoutput>
Do <cfdump var="#FindResourceDetailForDayResponse#" />
This may then be an CF XML Doc and you should be able to worth with it in CF
Copy link to clipboard
Copied
ColdFusion has several functions for working with XML Document Object Models (DOM).
You can read about working with XML in CF here: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec133ba-7fd9.html
The function you will get the most use out of is XMLSearch() which will require you to learn a bit of XPath (which is pretty cool, but can be as confusing as regex).
XPath search queries will allow you to dig through complex XML and retrieve nodes that you can then iterate over to accomplish what you probably need.
If you have a more specific question, please reply with it.
Jason
Copy link to clipboard
Copied
This:
org.tempuri.FindResourceDetailForDayResponseFindResourceDetailForDayResult@13d9efc
is a Java reference to an object in memory. That object probably contains the XML, as well as methods to interact with that XML.
What do you get when you use CFDUMP to view FindResourceDetailForDayResponse?
To interact with the XML once you get it, CF lets you treat XML documents as if they were nested arrays and structures. So, you can iterate over them using native CF operations and functions. You can also use XML DOM API calls like you would in many other environments. Finally, you can use XPath to match nodes anywhere in your XML.
Dave Watts, CTO, Fig Leaf Software
http://www.figleaf.com/
http://training.figleaf.com/
Fig Leaf Software is a Veteran-Owned Small Business (VOSB) on
GSA Schedule, and provides the highest caliber vendor-authorized
instruction at our training centers, online, or onsite.
Copy link to clipboard
Copied
That's what I get when I run cfdump
Copy link to clipboard
Copied
Try dumping get_any().
Dave Watts, CTO, Fig Leaf Software
http://www.figleaf.com/
http://training.figleaf.com/
Fig Leaf Software is a Veteran-Owned Small Business (VOSB) on
GSA Schedule, and provides the highest caliber vendor-authorized
instruction at our training centers, online, or onsite.
Copy link to clipboard
Copied
It returns back a longer list with what looks like would be functions that would be used for looping thru the XML i.e. "getAllAttributes", "getChildren", "getElementName", "getEnvelope"
Copy link to clipboard
Copied
Well, try calling some of those and see what happens!
Dave Watts, CTO, Fig Leaf Software
http://www.figleaf.com/
http://training.figleaf.com/
Fig Leaf Software is a Veteran-Owned Small Business (VOSB) on
GSA Schedule, and provides the highest caliber vendor-authorized
instruction at our training centers, online, or onsite.
Copy link to clipboard
Copied
If it makes any difference here's the entire output I get when I run the WSDL thru SoupUI
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<FindResourceDetailForDayResponse xmlns="http://tempuri.org/">
<FindResourceDetailForDayResult>
<xs:schema id="calendar" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="calendar" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Dwc-Room-02">
<xs:complexType>
<xs:sequence>
<xs:element name="StartTime" type="xs:string" minOccurs="0"/>
<xs:element name="EndTime" type="xs:string" minOccurs="0"/>
<xs:element name="BusyType" type="xs:string" minOccurs="0"/>
<xs:element name="Subject" type="xs:string" minOccurs="0"/>
<xs:element name="Location" type="xs:string" minOccurs="0"/>
<xs:element name="IsException" type="xs:string" minOccurs="0"/>
<xs:element name="IsMeeting" type="xs:string" minOccurs="0"/>
<xs:element name="IsPrivate" type="xs:string" minOccurs="0"/>
<xs:element name="IsRecurring" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Dwc-Room-01">
<xs:complexType>
<xs:sequence>
<xs:element name="StartTime" type="xs:string" minOccurs="0"/>
<xs:element name="EndTime" type="xs:string" minOccurs="0"/>
<xs:element name="BusyType" type="xs:string" minOccurs="0"/>
<xs:element name="Subject" type="xs:string" minOccurs="0"/>
<xs:element name="Location" type="xs:string" minOccurs="0"/>
<xs:element name="IsException" type="xs:string" minOccurs="0"/>
<xs:element name="IsMeeting" type="xs:string" minOccurs="0"/>
<xs:element name="IsPrivate" type="xs:string" minOccurs="0"/>
<xs:element name="IsRecurring" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<calendar xmlns="">
<Dwc-Room-02 diffgr:id="Dwc-Room-021" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 11:00:00 AM</StartTime>
<EndTime>10/6/2010 12:00:00 PM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Construction Meeting</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-02>
<Dwc-Room-01 diffgr:id="Dwc-Room-011" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 9:00:00 AM</StartTime>
<EndTime>10/6/2010 11:00:00 AM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Leadership Meeting</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-01>
<Dwc-Room-01 diffgr:id="Dwc-Room-012" msdata:rowOrder="1" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 12:00:00 PM</StartTime>
<EndTime>10/6/2010 2:00:00 PM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Strategic Conversation</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-01>
<Dwc-Room-01 diffgr:id="Dwc-Room-013" msdata:rowOrder="2" diffgr:hasChanges="inserted">
<StartTime>10/6/2010 2:00:00 PM</StartTime>
<EndTime>10/6/2010 3:00:00 PM</EndTime>
<BusyType>Busy</BusyType>
<Subject>Board Meeting</Subject>
<Location/>
<IsException>False</IsException>
<IsMeeting>False</IsMeeting>
<IsPrivate>False</IsPrivate>
<IsRecurring>False</IsRecurring>
</Dwc-Room-01>
</calendar>
</diffgr:diffgram>
</FindResourceDetailForDayResult>
</FindResourceDetailForDayResponse>
</soap:Body>
</soap:Envelope>
Copy link to clipboard
Copied
What you are getting back is actually a http response and you need to
get at the soap body inside it
so for my returnVariable which I've called httpResponse - I do the following
<cfif find( "200", #httpResponse.statusCode# )>
<!--- Parse the XML SOAP response. --->
<cfset soapResponse = xmlParse( #httpResponse.fileContent# ) />
<!-- write a copy of the response to the file system -->
<cffile action="write"
file="#session.server_root#/xmlOrders/#now()_response.xml"
output="#soapResponse#" >
<!---
Query for the response nodes using XPath. Because the
SOAP XML document has name spaces, querying the document
becomes a little funky. Rather than accessing the node
name directly, we have to use its local-name().
--->
<cfset responseNodes = xmlSearch(
#soapResponse#,
"//*[ local-name()='SOL_Acknowledgement']"
) />
</cfif>
Hope that helps
Copy link to clipboard
Copied
Here's my latest attempt. It seems to blow up around the CF struct-style XML node access attempt at the very bottom. The error I get is "
<cfsavecontent variable="soapBody">
<cfoutput>
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<FindResourceDetailForDay xmlns="http://tempuri.org/">
<c>Deerwood</c>
<d></d>
</FindResourceDetailForDay>
</soap:Body>
</soap:Envelope>
</cfoutput>
</cfsavecontent>
<cfhttp
url="http://webservice/WSExchangeMeetingRooms/exchange.asmx"
method="post"
result="httpResponse">
<cfhttpparam
type="header"
name="SOAPAction"
value="http://tempuri.org/FindResourceDetailForDay"
/>
<cfhttpparam
type="header"
name="accept-encoding"
value="no-compression"
/>
<cfhttpparam
type="xml"
value="#trim( soapBody )#"
/>
</cfhttp>
<cfif find( "200", httpResponse.statusCode )>
<!--- Parse the XML SOAP response. --->
<cfset soapResponse = xmlParse( httpResponse.fileContent ) />
<cfset responseNodes = xmlSearch(
soapResponse,
"//*[ local-name() = 'FindResourceDetailForDayResponse' ]"
) />
<cfoutput>
Code: #responseNodes[ 1 ].Code.xmlText#
<br />
Success: #responseNodes[ 1 ].Message.xmlText#
</cfoutput>
</cfif>
Copy link to clipboard
Copied
I would highly recommend using cfdump while you are debugging this issue. It will keep you away from getting sidetracked from the real issue. So instead of cfoutput'ing your variables just cfdump the entire structure. That way you can get a better picture of what is happening (or not).
Instead of this:
<cfoutput>
Code: #responseNodes[ 1 ].Code.xmlText#
<br />
Success: #responseNodes[ 1 ].Message.xmlText#
</cfoutput>
Do this:
<cfdump var="#responseNodes#">
Copy link to clipboard
Copied
SOAP means you have to send a SOAP XML to the web service. Do something like:
<!--- WSDL --->
<cfset wsdl_url="http://dwc-dreiman-w7e/WSExchangeMeetingRooms/exchange.asmx?WSDL">
<cftry>
<!--- Compose SOAP message to send to Web Service--->
<cfsavecontent variable="soap"><?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns:requestParameterName soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns="http://your_own_namespace_url">
<c xsi:type="xsd:string">bkbk</c>
<d xsi:type="xsd:string">test message from bkbk</d>
</ns:requestParameterName>
</soapenv:Body>
</soapenv:Envelope>
</cfsavecontent>
<!--- Invoke web service to send message--->
<cfhttp url="#wsdl_url#" method="post" >
<cfhttpparam type="header" name="content-type" value="text/xml">
<cfhttpparam type="header" name="SOAPAction" value="">
<cfhttpparam type="header" name="content-length" value="#len(soap)#">
<cfhttpparam type="header" name="charset" value="utf-8">
<cfhttpparam type="xml" name="message" value="#trim(soap)#">
</cfhttp>
<p><cfoutput>#xmlFormat(cfhttp.fileContent)#</cfoutput> </p>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
Copy link to clipboard
Copied
Thanks BKBK, that worked for me. Now I'm getting the XML returned from the webservice. Now I just need to be able to query the XML data but I think I can find/figure that out on my own. Thanks everyone for the help.
Copy link to clipboard
Copied
I was having this same issue and found a way to get at the values while still using the cfinvoke method instead of using cfhttp. To re-iterate when I made a cfinvoke call to the web service and dumped the result I would see an object dump with methods but no values (not the soap response I was expecting). You are able to retrieve the values from the service call by utilizing those methods that you see returned in the object. So for example, in this post a cfinvoke call was made to the web service and the result was stored in return variable "FindResourceDetailForDayResponse". The cfdump that was included shows the methods returned for that web service. In order to get the actual data from the call you can reference them like this for simple values: FindResourceDetailForDayResponse.getSimpleValue(). For complex values (like in the example from this post) you must dig a little deeper. If you keep cfdump'ing the returned methods you will finally get to the simple values. Then it is just a matter of calling each method in turn, like: FindResourceDetailForDayResponse.get_any().getStartTime() and FindResourceDetailForDayResponse.get_any().getEndTime() etc.
I know this is an old post but I just wanted to get this info out here because I haven't seen it mentioned anywhere else. You can certainly call the webservice using cfhttp as others have mentioned but then you need to deal with the resulting XML object. By calling the methods as I have shown you can access the values directly without the need to traverse the XML tree. If there is an issue with processing the soap response in this way then please let me know. It seems to be working for me.
Copy link to clipboard
Copied
Miguel - one thing I would watch out for is if one of the properties associated with a getter methods does not contain a value, you will get a NULL value back. In ColdFusion setting a variable to a NULL value will remove that variable from the memory space and give you a variable is not defined error when you try to use it. Typically this is not a huge issue, but .NET based web services are the worst at this sort of thing (returning NULL values, that is). I always caution users who are consuming web services using the <cfinvoke> method to check all of their getMethod() calls for NULL values or use an isdefined() check before using the variable. Rolling that checking logic into a UDF makes it a little easier to implement.
One advantage that the SOAP method has is that since you are dealing with native XML, it is a little easier to handle missing elements/attributes from your web service call.