function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
David BermanDavid Berman 

How to parse badly-formed JSON

If I had JSON that looked like this:
 { "user" : { "name" : "Simon Fell", "twitter" : "@superfell" } }, then I would set up a User class with the name and twitter properties.
In my case my JSON looks like this:
{"count":2,"users":
{"5599357":{"full_name":"Accounting","photo_path":"https://....s3.amazonaws.com/attachments/final/2015-06-09/5599357/2928b4_default","email_address":"accounting@acme.com","headline":"","account_id":"3473215","id":"5599357"},

"5752807":{"full_name":"JDoe","photo_path":"https://.../default.png","email_address":"jdoe@acme.com","headline":null,"account_id":"3783877","id":"5752807"}}}

The problem I'm facing is that the id (e.g. 5599357, 5752807) is repeated infront of the key/value pairs that follows.

Could someone suggest how I could parse out the information into a User class/object with attributes full_name, photo_path, email_address, headline, account_id and id?

By the way this is JSON returned from Mavenlink.
Thanks!


 
KevinPKevinP
with non-standard json, you really have two options:
1: Use explicit parsing. Json2apex.herokuapp.com can help generate that code. 
2: using Text manipulation methods to massage the incoming json string before parsing it. 
David BermanDavid Berman

I tried option 1, but it would just create a separate class for each id (e.g. 5599357, 5752807, both with the same full_name, id, etc. attributes), so that's not viable solution... unless there's a programmatic way whereby a scheduled Apex job could call that heroku app and somehow return all those numberic classes?

Can you help me with option 2, given the above example? I'm a bit at a loss as to where to start.  Thanks..
KevinPKevinP
You’ll need to use the String Methods to turn your users {} object into an array of user Objects i.e.: “Users”:[{blah…},{blah…}]
David BermanDavid Berman
Here's the code I'm running.  About 2/3s down the last if-statement block is causing an issue, and I don't know why.  Commenting it out makes the code run, uncommented it fails without explanation (I'm running it in the developer console):
httpRequest reqWorkspaces = new httpRequest();
reqWorkspaces.setMethod('GET');
reqWorkspaces.setEndpoint('https://api.mavenlink.com/api/v1/time_entries.json'+
                          '?created_after=2015-08-01T000000&created_before=2015-08-16T000000&page=1&per_page=20');
reqWorkspaces.setHeader('Authorization', 'Bearer xxxxxxxx');
reqWorkspaces.setTimeout(120000);
httpResponse resWorkspaces = new http().send(reqWorkspaces);

JSONParser parserCount = JSON.createParser(resWorkspaces.getBody());
Integer iCountTimecards = 0;
Integer iNumberOfBatches = 0;

while(parserCount.nextToken() != null)
{
	if((parserCount.getCurrentToken() == JSONToken.FIELD_NAME) && (parserCount.getText() == 'count'))
    {
        parserCount.nextToken();
        iCountTimecards = Integer.valueOf(parserCount.getText());
    }
}

SYSTEM.DEBUG('+++++ iCountTimecards: ' + iCountTimecards);

Map<String, String> mapKeyValue = new Map<String, String>();
Map<String, Map<String, String>> mapJSON = new Map<String, Map<String, String>>();

if(iCountTimecards > 0)
{
	iNumberOfBatches = Math.round(iCountTimecards / 200) + 1;
    
SYSTEM.DEBUG('+++++ iNumberOfBatches: ' + iNumberOfBatches);

	reqWorkspaces.setTimeout(120000);
    
	for(Integer iBatchNum = 1; iBatchNum <= iNumberOfBatches; iBatchNum++) 
    {

		reqWorkspaces.setEndpoint('https://api.mavenlink.com/api/v1/time_entries.json'+
                                  '?created_after=2015-08-01T000000&created_before=2015-16-01T000000&page=' + iBatchNum );
	
		resWorkspaces = new http().send(reqWorkspaces);
		
		JSONParser parser = JSON.createParser(resWorkspaces.getBody());
        
		String strTCID = '';
		String strProjectID = '';
		String strUserID = '';
		String strApproved = '';
		String strBillable = '';
		String strCreatedAt = ''; 
		String strUpdatedAt = '';
		String strDatePerformed = '';
		String strTimeInMinutes = '';
		String strRateInCents = '';
		String strNotes = '';
		String strStoryID = '';
        
		while(parser.nextToken() != null) 
		{
		    if(parser.getCurrentToken() == JSONToken.FIELD_NAME) 
		    {
                if(parser.getText() == 'created_at')
                {
                    parser.nextToken();
                    strCreatedAt = parser.getText();
                }
                
                if(parser.getText() == 'updated_at')
                {
                    parser.nextToken();
                    strUpdatedAt = parser.getText();
                }
                
                if(parser.getText() == 'date_performed')
                {
                    parser.nextToken();
                    strDatePerformed = parser.getText();
                }
                
                if(parser.getText() == 'time_in_minutes')
                {
                    parser.nextToken();
                    strTimeInMinutes = parser.getText();
                }
                
                if(parser.getText() == 'billable')
                {
                    parser.nextToken();
                    strBillable = parser.getText();
                }
                
                if(parser.getText() == 'notes')
                {
                    parser.nextToken();
                    strNotes = parser.getText();
                }
                
                if(parser.getText() == 'rate_in_cents')
                {
                    parser.nextToken();
                    strRateInCents = parser.getText();
                }
                
                if(parser.getText() == 'approved')
                {
                    parser.nextToken();
                    strApproved = parser.getText();
                }
                
                if(parser.getText() == 'story_id')
                {
                    parser.nextToken();
                    strStoryID = parser.getText();
                }
                
                if(parser.getText() == 'workspace_id')
                {
                    parser.nextToken();
		        	strProjectID = parser.getText();
                }
		        		    		    
                if(parser.getText() == 'user_id') 
                {
                    parser.nextToken();
                    strUserID = parser.getText();
                }
                
 // Commenting out the next 'if' block causes a successful execution... leaving it as is
 // causes an unknown failure
                
                if(parser.getText() == 'id')
                {
                    parser.nextToken();
                    strTCID = parser.getText();
                    
                    mapKeyValue.put('id', strTCID);
                    mapKeyValue.put('workspace_id', strProjectID);
                    mapKeyValue.put('created_at', strCreatedAt);
                    mapKeyValue.put('updated_at', strUpdatedAt);
                    mapKeyValue.put('date_performed', strDatePerformed);
                    mapKeyValue.put('time_in_minutes', strTimeInMinutes);
                    mapKeyValue.put('billable', strBillable);
                    mapKeyValue.put('notes', strNotes);
                    mapKeyValue.put('rate_in_cents', strRateInCents);
                    mapKeyValue.put('approved', strApproved);
                    mapKeyValue.put('story_id', strStoryID);
                    mapKeyValue.put('user_id', strUserID);
                    
                    mapJSON.put(strTCID, mapKeyValue);
                    mapKeyValue.clear();
                    
                }

                
            } // if(parser.getCurrentToken() == JSONToken.FIELD_NAME) 

		} // while(parser.nextToken() != null) 
        
	} // for(Integer iBatchNum = 1; iBatchNum <= iNumberOfBatches; iBatchNum++) 
} // if(iCountTimecards > 0)