3

I have an api call that gets survey results from a 3rd party. I then DeserializeJSON the result and it looks like this (n.b structs within the questionResults have been minimised for space):

enter image description here

I then loop through the first level and can pull the first level values (eg deviceName id etc) however I cant seem to find a way of getting the questionResults data. As specially I need the questionText and resultValue variables. (within the questionResults there are always 11 array results, each with identical setup structs)

Currently I'm using the following code:

<cfhttp url="#myurl#" method="POST" result="myresult">
  <cfhttpparam type="URL" name="apiKey" value="#apiKey#">
  <cfhttpparam type="URL" name="SurveyId" value="#SurveyId#">       
</cfhttp>

<cfset recordData=DeserializeJSON(#myresult.filecontent#)>

<cfdump var="#recordData#">

<cfloop from="1" to="#ArrayLen(recordData)#" index="i">
   <cfoutput>
     <strong>Record ID:</strong> #recordData[i].id#<br>

      <cfloop from="1" to="#ArrayLen(recordData[i])#" index="j">
            #recordData[i][j]#<br>
      </cfloop>
   </cfoutput>
   <hr> 
 </cfloop>

But get the error "Struct cannot be used as an array"

Any advice on how to get the data that I'm after?

Sam Allen
  • 589
  • 4
  • 6
  • 16
  • This line ` - `recordData[i]`is a struct. You can not use the for loop. `recordData[i].questionResult` is an array you can loop. – Bernhard Döbler Apr 27 '18 at 11:48
  • What data points do you need out of your JSON string? And can you post an example of the returned JSON? – Shawn Apr 27 '18 at 13:50

3 Answers3

2

I think that when you are looping through structures or arrays or pretty much anything, script syntax is much easier to visualize.

NOTE: I can't access my Gists to save it for TryCF right now.

First, I setup my "JSON" value:

<cfscript>

myresult.filecontent = '[
    {
        deviceIdentifier: "asdf" ,
        deviceName : "localiPad1" ,
        id : "23155736" ,
        otherStuff : "adsfasdfasd" ,
        questionResults : [
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "G8N9" ,
                questionText : "Select User" ,
                questionType : "Text" ,
                resultValue : "Beatriz Pinho"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "2" ,
                questionText : "Question2" ,
                questionType : "Text" ,
                resultValue : "Answer2"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "3" ,
                questionText : "Question3" ,
                questionType : "Text" ,
                resultValue : "Answer3"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "4" ,
                questionText : "Question4" ,
                questionType : "Text" ,
                resultValue : "Answer4"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "5" ,
                questionText : "Question5" ,
                questionType : "Text" ,
                resultValue : "Answer5"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "6" ,
                questionText : "Question6" ,
                questionType : "Text" ,
                resultValue : "Answer6"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "7" ,
                questionText : "Question7" ,
                questionType : "Text" ,
                resultValue : "Answer7"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "8" ,
                questionText : "Question8" ,
                questionType : "Text" ,
                resultValue : "Answer8"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "9" ,
                questionText : "Question9" ,
                questionType : "Text" ,
                resultValue : "Answer9"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "10" ,
                questionText : "Question10" ,
                questionType : "Text" ,
                resultValue : "Answer10"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "11" ,
                questionText : "Question11" ,
                questionType : "Text" ,
                resultValue : "Answer11"
            } 
        ] ,
        moreOtherStuff : "asdfasdfasdfasd"
    } ,
    {
        deviceIdentifier: "fdsa" ,
        deviceName : "localiPad2" ,
        id : "2" ,
        otherStuff : "adsfasdfasd" ,
        questionResults : [
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "G8N9" ,
                questionText : "Select User" ,
                questionType : "Text" ,
                resultValue : "Silent Bob"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "2" ,
                questionText : "Question2" ,
                questionType : "Text" ,
                resultValue : "Answer2"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "3" ,
                questionText : "Question3" ,
                questionType : "Text" ,
                resultValue : "Answer3"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "4" ,
                questionText : "Question4" ,
                questionType : "Text" ,
                resultValue : "Answer4"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "5" ,
                questionText : "Question5" ,
                questionType : "Text" ,
                resultValue : "Answer5"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "6" ,
                questionText : "Question6" ,
                questionType : "Text" ,
                resultValue : "Answer6"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "7" ,
                questionText : "Question7" ,
                questionType : "Text" ,
                resultValue : "Answer7"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "8" ,
                questionText : "Question8" ,
                questionType : "Text" ,
                resultValue : "Answer8"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "9" ,
                questionText : "Question9" ,
                questionType : "Text" ,
                resultValue : "Answer9"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "10" ,
                questionText : "Question10" ,
                questionType : "Text" ,
                resultValue : "Answer10"
            } ,
            {
                answerDate : "2018-04-26T09:25:55:55.0000000" ,
                questionIdentifier : "11" ,
                questionText : "Question11" ,
                questionType : "Text" ,
                resultValue : "Answer11"
            } 
        ] ,
        moreOtherStuff : "asdfasdfasdfasd"
    }
]' ;

I created a JSON variable that simulates what you get returned from your http request. I'll then deserialize the JSON from that.

recordData = deserializeJSON(myresult.filecontent) ;

Which gives me the nice array with structs and other arrays in it.

This is the part that I find much easier in script.

for ( var i IN recordData ) {  // loop through the outer array

    writeOutput("<strong>Record ID:</strong>" & i.id & "<br>") ;

    for ( var j IN i.questionResults ) { // loop through each questionResults
        writeOutput(
            j.questionIdentifier & " - " & 
            j.questionText
            &  " >> " & 
            j.resultValue 
            & " ------- " &
            j.answerDate
            & "<br>"
        ) ;
    }
}

And close my script.

</cfscript>

If I could get my TryCF.com code to display correctly, you'd see this returns:

Record ID:23155736
G8N9 - Select User >> Beatriz Pinho ------- 2018-04-26T09:25:55:55.0000000
2 - Question2 >> Answer2 ------- 2018-04-26T09:25:55:55.0000000
3 - Question3 >> Answer3 ------- 2018-04-26T09:25:55:55.0000000
4 - Question4 >> Answer4 ------- 2018-04-26T09:25:55:55.0000000
5 - Question5 >> Answer5 ------- 2018-04-26T09:25:55:55.0000000
6 - Question6 >> Answer6 ------- 2018-04-26T09:25:55:55.0000000
7 - Question7 >> Answer7 ------- 2018-04-26T09:25:55:55.0000000
8 - Question8 >> Answer8 ------- 2018-04-26T09:25:55:55.0000000
9 - Question9 >> Answer9 ------- 2018-04-26T09:25:55:55.0000000
10 - Question10 >> Answer10 ------- 2018-04-26T09:25:55:55.0000000
11 - Question11 >> Answer11 ------- 2018-04-26T09:25:55:55.0000000
Record ID:2
G8N9 - Select User >> Silent Bob ------- 2018-04-26T09:25:55:55.0000000
2 - Question2 >> Answer2 ------- 2018-04-26T09:25:55:55.0000000
3 - Question3 >> Answer3 ------- 2018-04-26T09:25:55:55.0000000
4 - Question4 >> Answer4 ------- 2018-04-26T09:25:55:55.0000000
5 - Question5 >> Answer5 ------- 2018-04-26T09:25:55:55.0000000
6 - Question6 >> Answer6 ------- 2018-04-26T09:25:55:55.0000000
7 - Question7 >> Answer7 ------- 2018-04-26T09:25:55:55.0000000
8 - Question8 >> Answer8 ------- 2018-04-26T09:25:55:55.0000000
9 - Question9 >> Answer9 ------- 2018-04-26T09:25:55:55.0000000
10 - Question10 >> Answer10 ------- 2018-04-26T09:25:55:55.0000000
11 - Question11 >> Answer11 ------- 2018-04-26T09:25:55:55.0000000

NOTE: I'm running this in Lucee. ACF doesn't like my JSON parsing, and I haven't dug through it to find which character it doesn't like. It still works though. :-)

Shawn
  • 4,758
  • 1
  • 20
  • 29
1

From your sample code it looks like you are referencing the same initial array in your second loop. That looks wrong to me. Try this instead.

<cfloop from="1" to="#ArrayLen(recordData)#" index="i">
    <cfoutput>
        <strong>Record ID:</strong> #recordData[i].id#<br>

        <cfloop from="1" to="#ArrayLen(recordData[i].questionResults)#" index="j">
            <cfdump var="#recordData[i].questionResults[j]#">
        </cfloop>
    </cfoutput>
    <hr> 
</cfloop>

I changed this <cfloop from="1" to="#ArrayLen(recordData[i])#" index="j"> to this <cfloop from="1" to="#ArrayLen(recordData[i].questionResults)#" index="j">

Update

In response to your comment, I updated my code example by changing this code #recordData[i][j]#<br> to this code <cfdump var="#recordData[i].questionResults[j]#"> as you cannot just simply output complex values as the error you reported stated.

You should be able to reference the questionText data (and other elements) like this #recordData[i].questionResults[j].questionText#.

Miguel-F
  • 13,450
  • 6
  • 38
  • 63
  • Thanks for your reply, I'm now getting this error "Complex object types cannot be converted to simple values. The expression has requested a variable or an intermediate expression result as a simple value. However, the result cannot be converted to a simple value. Simple values are strings, numbers, boolean values, and date/time values. Queries, arrays, and COM objects are examples of complex values." – Sam Allen Apr 27 '18 at 12:31
  • That's because of how you are referencing the second array. Sorry I didn't catch that in my original answer. I have updated the answer to dump that value instead. – Miguel-F Apr 27 '18 at 15:37
  • @SamAllen - Unless there's a reason you must use for/to loops, try using ``. With "array" loops the `index` is the array element, so less moving pieces. Easier to work with imo. – SOS Apr 27 '18 at 16:11
1

You have an array of structures and one of the structure elements is another array of structures named questionResults. I suggest this approach.

<cfloop array="#recordData#" index="ThisStructure">
do the easy stuff 
<cfif StructkeyExists(ThisStructure, "questionResults">
loop through that array and process it
closing tags
Dan Bracuk
  • 20,699
  • 4
  • 26
  • 43