?
Solved

Coldfusion XML Soap Call & Conditional Logic

Posted on 2012-04-04
9
Medium Priority
?
400 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

 
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
 
LVL 52

Accepted Solution

by:
_agx_ earned 2000 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

Major Serverless Shift

Comparison of major players like AWS, Microsoft Azure, IBM Bluemix, and Google Cloud Platform

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Browsers only know CSS so your awesome SASS code needs to be translated into normal CSS. Here I'll try to explain what you should aim for in order to take full advantage of SASS.
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).
Suggested Courses

752 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