5

Following my previous question here I've been dealing with some pretty crappy JSON for an assessment submission and trying to display it in a VF page as a table, ultimately with questions, available answers and the chosen answer indicated. As explained in the linked thread I had issues using standard deserialization into a wrapper class, and looking at how unstructured the information I need from the JSON is, parsing looks like the better approach. However this is all new to me so I'd really appreciate some advice on how I can grab and structure the information I need.

Example JSON:

{
    "quiz_submission_events": [
        {
            "id": "7775",
            "event_type": "submission_created",
            "event_data": {
                "quiz_version": 2,
                "quiz_data": [
                    {
                        "id": 320,
                        "regrade_option": "",
                        "points_possible": 0,
                        "correct_comments": "",
                        "incorrect_comments": "",
                        "neutral_comments": "",
                        "correct_comments_html": "",
                        "incorrect_comments_html": "",
                        "neutral_comments_html": "",
                        "question_type": "text_only_question",
                        "question_name": "Spacer",
                        "name": "Spacer",
                        "question_text": "\u003Cp\u003EIntro text test\u003C/p\u003E",
                        "answers": [

                        ],
                        "text_after_answers": "",
                        "assessment_question_id": null,
                        "position": 0,
                        "published_at": "2015-10-13T04:43:18Z"
                    },
                    {
                        "id": 321,
                        "regrade_option": "",
                        "points_possible": 1,
                        "correct_comments": "",
                        "incorrect_comments": "",
                        "neutral_comments": "",
                        "correct_comments_html": "",
                        "incorrect_comments_html": "",
                        "neutral_comments_html": "",
                        "question_type": "multiple_choice_question",
                        "question_name": "Question 1",
                        "name": "Question 1",
                        "question_text": "\u003Cp\u003ETest question 1\u003C/p\u003E",
                        "answers": [
                            {
                                "id": 6729,
                                "text": "Answer 1.1 I",
                                "html": "",
                                "comments": "",
                                "comments_html": "",
                                "weight": 0
                            },
                            {
                                "id": 8354,
                                "text": "Answer 1.2 I",
                                "html": "",
                                "comments": "",
                                "comments_html": "",
                                "weight": 100
                            },
                            {
                                "id": 5302,
                                "text": "",
                                "html": "\u003Cp\u003EAnswer 1.3 I\u003C/p\u003E",
                                "comments": "",
                                "comments_html": "",
                                "weight": 0
                            }
                        ],
                        "text_after_answers": "",
                        "assessment_question_id": 352,
                        "position": 1,
                        "published_at": "2015-10-13T04:43:18Z"
                    },
                    {
                        "id": 322,
                        "regrade_option": "",
                        "points_possible": 1,
                        "correct_comments": "",
                        "incorrect_comments": "",
                        "neutral_comments": "",
                        "correct_comments_html": "",
                        "incorrect_comments_html": "",
                        "neutral_comments_html": "",
                        "question_type": "essay_question",
                        "question_name": "Question 2",
                        "name": "Question 2",
                        "question_text": "\u003Cp\u003ETest essay question\u003C/p\u003E",
                        "answers": [

                        ],
                        "text_after_answers": "",
                        "comments": "",
                        "comments_html": "",
                        "assessment_question_id": 353,
                        "position": 2,
                        "published_at": "2015-10-13T04:43:18Z"
                    }
                ]
            },
            "created_at": "2015-10-13T04:48:07Z"
        },
        {
            "id": "7776",
            "event_type": "session_started",
            "event_data": {
                "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"
            },
            "created_at": "2015-10-13T04:48:10Z"
        },
        {
            "id": "7777",
            "event_type": "question_answered",
            "event_data": [
                {
                    "quiz_question_id": "320",
                    "answer": null
                },
                {
                    "quiz_question_id": "321",
                    "answer": null
                },
                {
                    "quiz_question_id": "322",
                    "answer": null
                }
            ],
            "created_at": "2015-10-13T04:48:11Z"
        },
        {
            "id": "7778",
            "event_type": "question_answered",
            "event_data": [
                {
                    "quiz_question_id": "321",
                    "answer": "8354"
                },
                {
                    "quiz_question_id": "322",
                    "answer": "\u003Cp\u003ET\u003C/p\u003E"
                }
            ],
            "created_at": "2015-10-13T04:48:16Z"
        },
        {
            "id": "7779",
            "event_type": "question_answered",
            "event_data": [
                {
                    "quiz_question_id": "322",
                    "answer": "\u003Cp\u003ETest essay answer\u003C/p\u003E"
                }
            ],
            "created_at": "2015-10-13T04:48:20Z"
        },
        {
            "id": "7780",
            "event_type": "question_viewed",
            "event_data": [
                "320",
                "321",
                "322"
            ],
            "created_at": "2015-10-13T04:48:24Z"
        },
        {
            "id": "7781",
            "event_type": "page_blurred",
            "event_data": null,
            "created_at": "2015-10-13T04:48:24Z"
        },
        {
            "id": "7782",
            "event_type": "page_focused",
            "event_data": null,
            "created_at": "2015-10-13T04:48:24Z"
        }
    ]
}

Things to know about the json structure:

  • quiz_submission_events object with event_type = "submission_created" hold the questions and available answers, each question a quiz_data object, where answers are offered (e.g. multiple choice) these are found within as answers objects
  • quiz_submission events objects with event_type = "question_answered" contain answers selected (for multiple choice) or answers typed (for essay questions) as event_data - event_data.quiz_question_id matching to quiz_data.id for the relevant question, and event_data.answer providing either an array of number strings relating to the quiz_data.answers.id (for multiple choice answer selected) or a text string (for essay answers typed).
  • The presence of event_data.answer as either an object or an array is an example of the inconsistencies in this JSON, but I may need these inconsistencies to recognise a multiple choice answer vs a text answer
  • There are multiple other quiz_submission_events provided which are not needed - those with event_type "question_answered" which do not contain the final answer (e.g. 4668) and any with event_type "session_started/question_viewed/question_flagged"

So, what I need help with is understanding how to use the parser to:

  • Parse into wrapper classes only the objects I need and the fields I need within them, by disregarding ones with particular field values e.g. event_type = "question_viewed"
  • Where there are multiple questions_answered submissions for a question id, only take the last one
  • use the ids between answer chosen, answers available and question to form the correct relationships between wrapper classes
  • And once I've organised this data in wrapper classes, how to display it in a visualforce table

A bigger question is, what is the better strategy to accomplish this?

  1. Parsing for specific keys as I'm doing here and trying to cobble them together into the model I want, or
  2. As per the linked thread, having wrapper classes that will catch and tolerate everything, then iterating through them to move the data I need into cleaner wrapper classes?

Json parse method and wrapper classes developed to just list quiz_data objects and answers if present (this compiles and runs without error but returns a single null quiz_data object):

    public List<quizData> getAnswers() {
        String reqQuizAnswers = "fetch url put here";
        //        System.debug(loggingLevel.Error, '*** URL called: ' + reqStudentList);
        Http h = new Http();

        HttpRequest req = new HttpRequest();
        req.setEndpoint(reqQuizAnswers);
        req.setMethod('GET');

        HttpResponse res = h.send(req);
        // Parse JSON response

        response = res.getBody();

        // clean up json inconsistencies to get limited parsing working
        response = response.replace('"event_data":{', '"event_data":[{');
        response = response.replace('},"created_at"', '}],"created_at"');
        String regex = '\"event_data\":\\[(\"\\d{2,}\",|\"\\d{2,}\")*\\],';
        Pattern regexPattern = Pattern.compile(regex); 
        Matcher regexMatcher = regexPattern.matcher(response);

        if(regexMatcher.find()) {
            System.debug(loggingLevel.Error, '*** Regex match found');
            response = response.replaceAll(regex, '');
        }
                System.debug(loggingLevel.Error, '*** response after cleansing: ' + response);
        JSONParser parser = JSON.createParser(response);
        // Get question data from quiz_data
        while (parser.nextToken() != null) {
            if (parser.getText() == 'quiz_data') {
                while (parser.nextToken() != null) {
                    // Advance to the start object marker to
                    //  find next quiz submission object.
                    if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
                        // Read entire quiz_data object, including its array of event data.
                        sub = (List<quizData>)parser.readValueAs(List<quizData>.class);

                        // Skip the child start array and start object markers.
                        parser.skipChildren();
                    }
                }
            }
        }
        system.debug('number of sub records: ' + sub.size());
        system.debug('sub list: ' + sub);
        for (quizData q : sub) {
            system.debug('question text: ' + q.question_text);
        }
        return sub;
    }       

    //Wrapper classes 

    public class quizData {
        public Integer id {get; set;}
        public String question_type {get; set;}
        public String question_name {get; set;}
        public String question_text {get; set;}
        public List<answers> answers {get; set;}

        public quizData(Integer qId, String qType, String qName, String qText, List<answers> qAns) {
            id = qId;
            question_type = qType;
            question_name = qName;
            question_text = qText;
            answers = qAns.clone();
        }
    }

    public class answers {
        public Integer id {get; set;}
        public Integer text {get; set;}
    }

} 

Basic visualforce page to display results:

<apex:page standardController="Account" extensions="TestJsonController">

    <p>{!Account.Name}</p>

    <apex:pageBlock title="Test json read">


            <apex:pageBlockTable value="{!answers}" var="q">
                <apex:column headerValue="Question Id">
                <apex:outputText value="{!q.id}"/>
                </apex:column>
                <apex:column headerValue="Question Type">
                <apex:outputText value="{!q.question_type}"/>
                </apex:column>
                <apex:column headerValue="Question Name">
                <apex:outputText value="{!q.question_name}"/>
                </apex:column>
                <apex:column headerValue="Question Text">
                <apex:outputText value="{!q.id}"/>
                </apex:column>
                <apex:column headerValue="Answers">
                <apex:outputText value="{!q.answers}"/>
                </apex:column>
            </apex:pageBlockTable>                        

        </apex:pageBlockSection>

    </apex:pageBlock>

</apex:page>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.