4

I am looping over an array of structures and trying to assign and store all key values. If I wrap inner loop in <cfoutput>, I am getting an error: "Complex object types cannot be converted to simple values". If I leave it out, then it does not work. What am I missing?

enter image description here

<cfif isJSON(httpResp.fileContent)>
    <cfset jsonData = deserializeJSON(httpResp.fileContent) />    

    <cfloop from="1" to="#arrayLen(jsonData)#" index="i">
        <cfset data = jsonData[i]>

        <!---<cfoutput>--->                 
        <cfloop collection="#data#" item="key">
            #key#:#data[key]#<br>
        </cfloop>       
        <!---</cfoutput>---> 

    </cfloop>

    <cfdump var="#jsonData#">

<cfelse>
      Did not receive a valid Json object
</cfif>

Here is the output:

#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
#key#:#data[key]#
2
  • You need to reference specific keys inside a cfoutput - can be difficult when the data is not the same length each time. With structs like that you'll maybe want to use StructFindKey(). If you expect similar data structure each time it should be easy enough to write conditional logic inside your loop. Commented Jul 16, 2019 at 23:29
  • I see that some of those key values are also structures themselves. So those cannot be outputted directly. Commented Jul 17, 2019 at 0:25

1 Answer 1

2

trying to assign and store all key values

While you could technically output all of the keys dynamically, if the ultimate goal is to manipulate and/or store the values, then dynamic looping probably isn't what you want anyway. To extract specific values, just reference the keys names explicitly - using dot-notation. For example:

<cfloop array="#jsonData#" index="prop">
    <cfoutput>
        <hr>confirmation = #prop.confirmation#
        <br>id = #prop.id#
        <br>label.carrier = #prop.label.carrier#
        <br>label.tracking = #prop.label.tracking#
        <br>order.created_at = #prop.order.created_at#
        <br>policy.logistic_code = #prop.policy.logistic_code#
        <br>policy.refund_code = #prop.policy.refund_code#
        <br>ref.order = #prop.ref.order#
        <br>state = #prop.state#
        ... 
    </cfoutput>
</cfloop>

However, to answer your question, the error message just means that cfoutput can only handle simple values. Since some of the values you're trying to display are actually structures (i.e. complex objects), like label and states, the cfoutput chokes when it tries to output them.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your help. Your solution worked. I do have one more question. Do I have to check for key values using StructKeyEXists()? I noticed that in second element of my array there is another struct inside of one of the states. I am not sure how to attach a picture to the comment to show it.
You'd only need it if a particular key is optional (i.e. doesn't always exist). Otherwise, just use the dot notation path of the key. Notice in your original dump "states" is the top level structure => with a child key "APPROVED" => with a grandchild key "at", so the path would be: #props.states.approved.at#
I updated the image in my original post. As you can see in states.refunded there are 3 keys in the second element of the array and only 2 keys in first. When I try: <cfif StructKeyEXists(jsonData,"totalRefunded")> <br>refund_amt = #i.states.refunded.transaction.totalRefunded# </cfif> I am receiving an error: You have attempted to dereference a scalar variable of type class coldfusion.runtime.Array as a structure with members.
The error is being caused by some other code. What you posted couldn't cause an error because the CFIF is never true - and the inner code #i.states.refunded.... never even executes. Unfortunately StructKeyExists can only handle a single, simple key name. To verify the nested key "transaction" exists, use <cfif structKeyExists( i.states.refunded, "transaction")>. That said, while I normally never recommend IsDefined, checking nested keys is one of the few things it does better. Just beware of scoping issues. Example: <cfif IsDefined("i.states.refunded.transaction.totalRefunded")>.
If this is CF2016, there's also the safe-navigation operator: jsonData?.i?.states?.refunded?.transactions?.totalRefunded. If any one of those keys doesn't exist, it will return undefined.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.