Solved

Coldfusion XML Soap Call & Conditional Logic

Posted on 2012-04-04
9
381 Views
Last Modified: 2012-06-21
I have a soap call that gets converted to an array.  I need to check to see if a variable from the array exists and I don't know how to do this because <cfif> does not accept my array value.

I have also uploaded this file to my server with a form that you can enter values to see the results I am getting.  I include a dump of the xml array and the query that I am creating. Unfortunately the soap call has a login and password, so I had to set these up in a database, so you won't be able to run this locally.

The link to access this page is:
http://burnsville.ensemblecreative.com/Members_C134_GetMembgersByCategory.cfm

Here is the code:
<!---*********************************************************************--->
<!---* NOTE: Feel free to remove the ctry catch to see line item errors. *--->
<!---*********************************************************************--->

<cftry>
<cfquery datasource="#DataSource#" name="getIDSSLogin">
	SELECT UserName, Password
    FROM idss
    WHERE ID = 1
</cfquery>

<!---This is form is temporary so I can test the category IDs for results--->
<cfform name="formTest">
	<input type="text" name="CategoryID">
    <input type="submit" name="SubmitCategory" value="Submit">
</cfform>
<p>A value that works: 3503</p>
<p>A value that fails: 3526 (error message is all the way at the bottom under the array)</p>
<p>NOTE: The dump of the array works fine. The error occurs when looping through the array to<br />
create the query. If the Address does not exist for one or more records, the error will occur.</p>
<p>The error looks like this:<br />
Element Address is undefined in a Java object of type class coldfusion.xml.XmlNodeList.</p>

<p>Sorry this is really slow because of the dump.</p>
<!---END Temporary Form--->

<!---This dump shows the category ID that is used in the search--->
<p>I dumped this to see what ID was used:
<cfdump var="#form#">

<!---If the CategoryID is entered in the form, show the results--->
<cfif IsDefined("Form.SubmitCategory")>
<!---Soap Call--->
<cfsavecontent variable="C134_GetMembersByCategoryBody">
	<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:Header>
        <AuthorizeHeader xmlns="http://ws.idssasp.com/Members.asmx">
        <UserName>#getIDSSLogin.UserName#</UserName>
        <Password>#getIDSSLogin.Password#</Password>
        </AuthorizeHeader>
        </soap:Header>
         <soap:Body>
            <C134_GetMembersByCategory xmlns="http://ws.idssasp.com/Members.asmx">
              <categoryIDs>#Form.CategoryID#</categoryIDs>
              <includeChildCategories>false</includeChildCategories>
              <includeAddresses>true</includeAddresses>
            </C134_GetMembersByCategory>
          </soap:Body>
        </soap:Envelope>
	</cfoutput>
</cfsavecontent>

<!---Take the soap call and convert it to something coldfusion can use--->
<!---Note: This part came from Ben Nadel's blog (see link next comment). I stripped out what I didn't need--->
<!---http://www.bennadel.com/blog/1809-Making-SOAP-Web-Service-Requests-With-ColdFusion-And-CFHTTP.htm--->
<cfhttp
	url="http://ws.idssasp.com/Members.asmx"
	method="post"
	result="httpResponse">
    <cfhttpparam
        type="header"
        name="SOAPAction"
        value="http://ws.idssasp.com/Members.asmx/C134_GetMembersByCategory"
        />
    <cfhttpparam
        type="header"
        name="accept-encoding"
        value="no-compression"
        />
    <cfhttpparam
		type="xml"
		value="#trim( C134_GetMembersByCategoryBody )#"
		/>
</cfhttp>

<!--- Parse the XML SOAP response. --->
<cfset C134_GetMembersByCategoryBody = xmlParse( httpResponse.fileContent ) />

<!---Set the values as a usable array--->
<cfset MembersByCategory = C134_GetMembersByCategoryBody["soap:Envelope"]["soap:Body"]["C134_GetMembersByCategoryResponse"]["C134_GetMembersByCategoryResult"].XmlChildren>

<p>This is a dump of the soap call as an array</p>
<cfdump var="#MembersByCategory#">

<!---Create a Query of the data--->
<cfset getMembersByCategory = QueryNew("MemberID, AccountName, Phone, SecondaryPhone, Website, Street, Suite, Address3, Address4, City, StateAbbr, PostalCode, GoogleMapQuery, ID, ParentID, Name, SortOrder")>

<!---********************************************************************************************************--->
<!---* NOTE: I have commented out the cfif statements that I need to put in place for the conditional logic *--->
<!---********************************************************************************************************--->

<cfloop FROM="1" TO="#arrayLen(MembersByCategory)#" index="i">
	<cfset memberValues = MembersByCategory[i].XmlChildren>
    <!---<cfif IsDefined('MembersByCategory[i]["Addresses"]["Address"]')>--->
    <cfset addressValues = MembersByCategory[i]["Addresses"]["Address"].XmlChildren>
    <!---</cfif>--->
    <cfset categoryValues = MembersByCategory[i]["Categories"]["MemberCategory134"].XmlChildren>

	<cfset queryAddRow(getMembersByCategory)>
	<cfset querySetCell(getMembersByCategory, "MemberID", memberValues[1]["XmlText"])>
	<cfset querySetCell(getMembersByCategory, "AccountName", memberValues[2]["XmlText"])>
    <!---Needs to be updated with phone index when Kyle gets this done. Currently using fax as a place holder--->
	<cfset querySetCell(getMembersByCategory, "Phone", memberValues[4]["XmlText"])> 
    <!---End Replace--->
	<cfset querySetCell(getMembersByCategory, "SecondaryPhone", memberValues[3]["XmlText"])>
	<cfset querySetCell(getMembersByCategory, "Website", memberValues[5]["XmlText"])>
    <!---<cfif IsDefined('MembersByCategory[i]["Addresses"]["Address"]')>--->
		<cfset querySetCell(getMembersByCategory, "Street", addressValues[2]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "Suite", addressValues[3]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "Address3", addressValues[4]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "Address4", addressValues[5]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "City", addressValues[6]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "StateAbbr", addressValues[8]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "PostalCode", addressValues[9]["XmlText"])>
    <!---<cfelse>
    	<cfset querySetCell(getMembersByCategory, "Street", "")>
        <cfset querySetCell(getMembersByCategory, "Suite", "")>
        <cfset querySetCell(getMembersByCategory, "Address3", "")>
        <cfset querySetCell(getMembersByCategory, "Address4", "")>
        <cfset querySetCell(getMembersByCategory, "City", "")>
        <cfset querySetCell(getMembersByCategory, "StateAbbr", "")>
        <cfset querySetCell(getMembersByCategory, "PostalCode", "")>
    </cfif>--->
    <cfset querySetCell(getMembersByCategory, "GoogleMapQuery", addressValues[12]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "ID", categoryValues[1]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "ParentID", categoryValues[2]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "Name", categoryValues[3]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "SortOrder", categoryValues[5]["XmlText"])>
</cfloop>
</cfif>
<p>Dump the query that is created:</p>
<cfdump var="#getMembersByCategory#">

<cfcatch>
<cfoutput>#cfcatch.Message#<br />
#cfcatch.Detail#</cfoutput>
</cfcatch>
</cftry>

Open in new window


The value that I am trying to check for is:
MembersByCategory[x]["Addresses"]["Address"] (see code - x is i in the code because this form thinks I am trying to italicize my something)

Note: If one record does not have this information does not have address information, it breaks the entire operation.

I have commented out the cfif's in the two sections that I need to apply this condition.  They are inside the loop.

Any help would be appreciated.
Members-C134-GetMembgersByCatego.txt
0
Comment
Question by:lonnyo
  • 4
  • 3
  • 2
9 Comments
 
LVL 4

Expert Comment

by:TechHelpr08210
ID: 37808270
I believe this function is what your looking for in the two positions yu mentioned.

Try replacing  your isdefined('') statements:

<cfif isdefined('MembersByCategory[i]["Addresses"]["Address"]')  >
<cfset addressValues = MembersByCategory[i]["Addresses"]["Address"].XmlChildren >
</cfif>

Open in new window


with the IsXMLelem() statement (see below).

<cfif Isxmlelem(MembersByCategory[i]["Addresses"]["Address"]) >
<cfset addressValues = MembersByCategory[i]["Addresses"]["Address"].XmlChildren >
</cfif>

Open in new window

0
 

Author Comment

by:lonnyo
ID: 37808498
I am still getting the same error:

Element Address is undefined in a Java object of type class coldfusion.xml.XmlNodeList.

That means it is getting inside the cfif regardless if it is true or false.

They said I could post the login information if you want to test this on your local computer

you can replace those two lines in the soap call with

<UserName>burnsville</UserName>
<Password>618b86b9-6ea0-421d-b4e4-a755619a5f53</Password>

Open in new window

0
 
LVL 52

Expert Comment

by:_agx_
ID: 37808570
<cfif isdefined('MembersByCategory[x]["Addresses"]["Address"]')  >

IsDefined doesn't allow structure notation, only dot notation.

Try
	
<cfif structKeyExists(MembersByCategory[ i ], "Addresses")
           and structKeyExists(MembersByCategory[i]["Addresses"], "Address")>
         it has an address ...
<cfelse>
         no address
</cfif>

Open in new window


Or copy it into a variable so you can use dot notation

      <cfset currMember = MembersByCategory[ i ]>
      <cfif IsDefined("currentCategory.Addresses.Address")>
             it has an address ...
       <cfelse>
              no address
       </cfif>
0
 
LVL 4

Expert Comment

by:TechHelpr08210
ID: 37808617
Here you go.

To solve your issue, I replaced the CFif statements with Try/Catch statements.

It works now!



<!---*********************************************************************--->
<!---* NOTE: Feel free to remove the ctry catch to see line item errors. *--->
<!---*********************************************************************--->

<cftry>
<!---<cfquery datasource="#DataSource#" name="getIDSSLogin">
	SELECT UserName, Password
    FROM idss
    WHERE ID = 1
</cfquery>--->

<!---This is form is temporary so I can test the category IDs for results--->
<cfform name="formTest">
	<input type="text" name="CategoryID">
    <input type="submit" name="SubmitCategory" value="Submit">
</cfform>
<p>A value that works: 3503</p>
<p>A value that fails: 3526 (error message is all the way at the bottom under the array)</p>
<p>NOTE: The dump of the array works fine. The error occurs when looping through the array to<br />
create the query. If the Address does not exist for one or more records, the error will occur.</p>
<p>The error looks like this:<br />
Element Address is undefined in a Java object of type class coldfusion.xml.XmlNodeList.</p>

<p>Sorry this is really slow because of the dump.</p>
<!---END Temporary Form--->

<!---This dump shows the category ID that is used in the search--->
<p>I dumped this to see what ID was used:
<cfdump var="#form#">

<!---If the CategoryID is entered in the form, show the results--->
<cfif IsDefined("Form.SubmitCategory")>
<!---Soap Call--->
<cfsavecontent variable="C134_GetMembersByCategoryBody">
	<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:Header>
        <AuthorizeHeader xmlns="http://ws.idssasp.com/Members.asmx">
        <UserName>burnsville</UserName>
		<Password>618b86b9-6ea0-421d-b4e4-a755619a5f53</Password>
        </AuthorizeHeader>
        </soap:Header>
         <soap:Body>
            <C134_GetMembersByCategory xmlns="http://ws.idssasp.com/Members.asmx">
              <categoryIDs>#Form.CategoryID#</categoryIDs>
              <includeChildCategories>false</includeChildCategories>
              <includeAddresses>true</includeAddresses>
            </C134_GetMembersByCategory>
          </soap:Body>
        </soap:Envelope>
	</cfoutput>
</cfsavecontent>

<!---Take the soap call and convert it to something coldfusion can use--->
<!---Note: This part came from Ben Nadel's blog (see link next comment). I stripped out what I didn't need--->
<!---http://www.bennadel.com/blog/1809-Making-SOAP-Web-Service-Requests-With-ColdFusion-And-CFHTTP.htm--->
<cfhttp
	url="http://ws.idssasp.com/Members.asmx"
	method="post"
	result="httpResponse">
    <cfhttpparam
        type="header"
        name="SOAPAction"
        value="http://ws.idssasp.com/Members.asmx/C134_GetMembersByCategory"
        />
    <cfhttpparam
        type="header"
        name="accept-encoding"
        value="no-compression"
        />
    <cfhttpparam
		type="xml"
		value="#trim( C134_GetMembersByCategoryBody )#"
		/>
</cfhttp>

<!--- Parse the XML SOAP response. --->
<cfset C134_GetMembersByCategoryBody = xmlParse( httpResponse.fileContent ) />

<!---Set the values as a usable array--->
<cfset MembersByCategory = C134_GetMembersByCategoryBody["soap:Envelope"]["soap:Body"]["C134_GetMembersByCategoryResponse"]["C134_GetMembersByCategoryResult"].XmlChildren>

<p>This is a dump of the soap call as an array</p>
<cfdump var="#MembersByCategory#">

<!---Create a Query of the data--->
<cfset getMembersByCategory = QueryNew("MemberID, AccountName, Phone, SecondaryPhone, Website, Street, Suite, Address3, Address4, City, StateAbbr, PostalCode, GoogleMapQuery, ID, ParentID, Name, SortOrder")>

<!---********************************************************************************************************--->
<!---* NOTE: I have commented out the cfif statements that I need to put in place for the conditional logic *--->
<!---********************************************************************************************************--->

<cfloop FROM="1" TO="#arrayLen(MembersByCategory)#" index="i">
	<cfset memberValues = MembersByCategory[i].XmlChildren>
    
	<cftry>
    <cfset addressValues = MembersByCategory[i]["Addresses"]["Address"].XmlChildren>
    <cfcatch type="expression"></cfcatch></cftry>
    <cfset categoryValues = MembersByCategory[i]["Categories"]["MemberCategory134"].XmlChildren>

	<cfset queryAddRow(getMembersByCategory)>
	<cfset querySetCell(getMembersByCategory, "MemberID", memberValues[1]["XmlText"])>
	<cfset querySetCell(getMembersByCategory, "AccountName", memberValues[2]["XmlText"])>
    <!---Needs to be updated with phone index when Kyle gets this done. Currently using fax as a place holder--->
	<cfset querySetCell(getMembersByCategory, "Phone", memberValues[4]["XmlText"])> 
    <!---End Replace--->
	<cfset querySetCell(getMembersByCategory, "SecondaryPhone", memberValues[3]["XmlText"])>
	<cfset querySetCell(getMembersByCategory, "Website", memberValues[5]["XmlText"])>
    
	<cftry> 
		<cfset querySetCell(getMembersByCategory, "Street", addressValues[2]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "Suite", addressValues[3]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "Address3", addressValues[4]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "Address4", addressValues[5]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "City", addressValues[6]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "StateAbbr", addressValues[8]["XmlText"])>
        <cfset querySetCell(getMembersByCategory, "PostalCode", addressValues[9]["XmlText"])>
    <cfcatch type="expression" >
    	<cfset querySetCell(getMembersByCategory, "Street", "")>
        <cfset querySetCell(getMembersByCategory, "Suite", "")>
        <cfset querySetCell(getMembersByCategory, "Address3", "")>
        <cfset querySetCell(getMembersByCategory, "Address4", "")>
        <cfset querySetCell(getMembersByCategory, "City", "")>
        <cfset querySetCell(getMembersByCategory, "StateAbbr", "")>
        <cfset querySetCell(getMembersByCategory, "PostalCode", "")>
    </cfcatch>
    </cftry>
    
    <cfset querySetCell(getMembersByCategory, "GoogleMapQuery", addressValues[12]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "ID", categoryValues[1]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "ParentID", categoryValues[2]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "Name", categoryValues[3]["XmlText"])>
    <cfset querySetCell(getMembersByCategory, "SortOrder", categoryValues[5]["XmlText"])>
</cfloop>
</cfif>
<p>Dump the query that is created:</p>
<cfdump var="#getMembersByCategory#">

<cfcatch>
<cfoutput>#cfcatch.Message#<br />
#cfcatch.Detail#</cfoutput>
</cfcatch>
</cftry>

Open in new window

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 52

Accepted Solution

by:
_agx_ earned 500 total points
ID: 37808642
It's cleaner to test for an elements existence with IsDefined or structKeyExists.  Though try/catch would work in this one case, it's less scalable and it's more expensive to throw exceptions than prevent them.
0
 
LVL 4

Expert Comment

by:TechHelpr08210
ID: 37808709
It's cleaner to test for an elements existence with IsDefined or structKeyExists.  Though try/catch would work in this one case, it's less scalable and it's more expensive to throw exceptions than prevent them.

Valid Point... no arguments...

However, they will need to rewrite thier all of thier XML variable references in this page to implement the cleaner solution.
0
 
LVL 52

Expert Comment

by:_agx_
ID: 37808783
Well you wouldn't do it for every element, because that would be crazy :) You have to trust the API. If it says an element is always present, you just take it on faith and code accordingly. Then let your general error handler deal with unexpected problems. Otherwise, the code would be ridiculously unmanageable. So you only need isDefined/structKeyExists on elements that are known to be optional, like "Address".
0
 

Author Closing Comment

by:lonnyo
ID: 37808794
Thank worked!  Thank you very much.  Never would have thought of that.
0
 
LVL 4

Expert Comment

by:TechHelpr08210
ID: 37808973
No problem, I'm glad it worked out!
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Preface In the first article: A Better Website Login System (http://www.experts-exchange.com/A_2902.html) I introduced the EE Collaborative Login System and its intended purpose. In this article I will discuss some of the design consideratio…
CFGRID Custom Functionality Series -  Part 1 Hi Guys, I was once asked how it is possible to to add a hyperlink in the cfgrid and open the window to show the data. Now this is quite simple, I have to use the EXT JS library for this and I achiev…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now