Coldfusion XML Soap Call & Conditional Logic

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
lonnyoAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

TechHelpr08210Commented:
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
lonnyoAuthor Commented:
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
_agx_Commented:
<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
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

TechHelpr08210Commented:
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
_agx_Commented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
TechHelpr08210Commented:
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
_agx_Commented:
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
lonnyoAuthor Commented:
Thank worked!  Thank you very much.  Never would have thought of that.
0
TechHelpr08210Commented:
No problem, I'm glad it worked out!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
ColdFusion Language

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.