Extract nested attribute value from JSON String using Apex

Salesforce offers two main ways to extract values from a JSON string
1) JSON.deserialize() This approach requires you to have a wrapper class/other valid entity to deserialize the data to.
2) JSON.createParser(jsonString) This approach requires you to loop through a bunch of confusing parser.nextToken() calls

In this article I am introducing an easy to use utility to extract inner attribute values from any JSON string. This is leveraging JSON.createParser(). But once you have this utility, you don't have to go through the parser.nextToken() confusion.

Example of use
Utils.extractAttributeFromJson('{"data":{"user":{"organization":{"id":"123"}}}}', 'data.user.organization.id');


public with sharing class Utils {
//If parser is at start of inner object or array, skipping till end of the section
public static JSONParser skipTillEndOfSection(JSONParser parser) {
if(parser != null && parser.getCurrentToken() == JSONToken.START_ARRAY) {
if(parser.getCurrentToken() == JSONToken.START_ARRAY) {
while(parser.getCurrentToken() != JSONToken.END_ARRAY) {
parser.nextToken();
if(parser.getCurrentToken() == JSONToken.START_ARRAY || parser.getCurrentToken() == JSONToken.START_OBJECT) {
skipTillEndOfSection(parser);
}
}
}else if(parser.getCurrentToken() == JSONToken.START_OBJECT) {
while(parser.getCurrentToken() != JSONToken.END_OBJECT) {
parser.nextToken();
if(parser.getCurrentToken() == JSONToken.START_ARRAY || parser.getCurrentToken() == JSONToken.START_OBJECT) {
skipTillEndOfSection(parser);
}
}
}
}
return parser;
}
/**************************************************************************************
* @Description This method extract value of inner attributes in a JSON
* @Param String - JSON string
* @Param String - JSON attribute path
* @Return String - This sample assumes returned value is a string
* @Example
* Utils.extractAttributeFromJson('{"data":{"user":{"organization":{"id":"123"}}}}', 'data.user.organization.id');
**************************************************************************************/
public static String extractAttributeFromJson(String jsonResponse, String attrString) {
if(String.isBlank(jsonResponse) || String.isBlank(attrString)) return null;
List<String> attrPath = attrString.split('\\.');
JSONParser parser = JSON.createParser(jsonResponse);
Integer index = 0;
parser.nextToken();
while(parser.nextToken() != null) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
if(attrPath[index] == parser.getText()) {
if(index == attrPath.size()-1) {
parser.nextToken();
return parser.getText();
}else if(parser.nextToken() == JSONToken.START_OBJECT) {
index++;
}
}
}else if(parser.getCurrentToken() == JSONToken.START_OBJECT || parser.getCurrentToken() == JSONToken.START_ARRAY) {
skipTillEndOfSection(parser);
}
}
return null;
}
}
view raw Utils.cls hosted with ❤ by GitHub

Please note that it will be more performant to use JSON.createParser() directly if you have multiple attributes to extract from the JSON.