Extracting JSON Keys from Two Dimensional Matrix - java

When dealing with a valid JSON which represents a two dimensional matrix:
[ { "a":1, "b":2 }, { "b":3, "c":4 }, { "c":6, "a":5 } ]
Using Java 1.8 and the json-simple lib:
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
Am able to obtain an individual row using the following?:
JSONParser parser = new JSONParser();
Object obj = parser.parse(args[0]);
JSONArray array = (JSONArray) obj;
System.out.println(array.get(0));
This outputs:
{"a":1,"b":2}
My question is how to extract the key values from this two dimensional matrix to output this:
'{ "a": [1,null,5], "b": [2,3,null], "c": [null,4,6] }'
Notice, that any variables that are missing from the row should have null inserted...

General solution could look like below:
Read JSON payload as ARRAY.
Find all possible keys in all JSON Object's in ARRAY and store them in KEYS set.
Iterate over all JSON Object's in ARRAY.
Iterate over all KEYS and get value or null from given JSON Object.
Using Java 8 features we can implement it as below:
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class JsonSimpleApp {
public static void main(String[] args) throws ParseException {
// input
String json = "[ { \"a\":1, \"b\":2 }, { \"b\":3, \"c\":4 }, { \"c\":6, \"a\":5 } ]";
// read as JSONArray
JSONParser parser = new JSONParser();
JSONArray array = (JSONArray) parser.parse(json);
// Find all possible keys
Set<String> keys = (Set<String>) array.stream().flatMap(i -> ((JSONObject) i).keySet().stream()).collect(Collectors.toSet());
// create result Map with KEY - LIST pair
Map<String, List<Object>> result = new HashMap<>();
keys.forEach(key -> result.put(key, new ArrayList<>()));
// Iterate over all JSONObject's
array.forEach(item -> {
JSONObject object = (JSONObject) item;
// For each possible key add a value or NULL to each list
keys.forEach(key -> result.get(key).add(object.remove(key)));
});
result.entrySet().forEach(System.out::println);
}
}
Above code prints:
a=[1, null, 5]
b=[2, 3, null]
c=[null, 4, 6]

You can acces in json by key. For example:
obj["key"][0]
Then you can take the value

Edited
Simply you can use JOLT for this purpose.
JSON to JSON transformation library written in Java where the
"specification" for the transform is itself a JSON document.
According to your scenario, you must Just:
1- Create a rule
2- Filter your input via this rule.
The JSON input is as follows
[
{
"a": 1,
"b": 2
},
{
"b": 3,
"c": 4
},
{
"c": 6,
"a": 5
}
]
The filter rule (JOLT spec) can be as follows
[
{
"operation": "shift",
"spec": {
"*": {
"a": "a",
"b": "b",
"c": "c"
}
}
}
]
result
{
"a" : [ 1, 5 ],
"b" : [ 2, 3 ],
"c" : [ 4, 6 ]
}
You can test the aforementioned solution in here
Java code for applying the aforementioned items in java
public class CustomJsonTransformer {
public static void main(String[] args) throws Exception {
//Get filter (JOLT SPEC)
List<Object> specs = JsonUtils.classpathToList("/filter.json");
Chainr chainr = Chainr.fromSpec(specs);
//Get input JSON
Object inputJSON = JsonUtils.classpathToObject("/input.json");
//Do filter
Object transformedOutput = chainr.transform(inputJSON);
//Result
System.out.println(JsonUtils.toPrettyJsonString(transformedOutput));
}
}
1- This guide shows a pretty good sample on JOLT in java
2- Complete documentation of JOLT is here
Notice that, with the help of JOLT documentation, you can make the rule more complicated or easier (My rule was just a simple one)

Related

Merge multiple JSONObjects (possibly containing arrays) in Java [duplicate]

This question already has answers here:
Merge/Extend JSON Objects using Gson in Java
(4 answers)
Closed 1 year ago.
Given this JSON:
{
"contact_data": [
"address/all",
"telephone/us"
],
"financial_data": [
"bank_account_number/all",
"bank_account_number/uk",
"credit_card_numbers"
]
}
and this JSON:
{
"financial_data": [
"credit_card_numbers",
"bank_account_number/ca",
"bank_account_number/all"
],
"government_id": [
"driving_license/americas"
],
"sensitive_data": [
"racial_ethnic_origin"
]
}
I want to merge these to look like this:
{
"contact_data": [
"address/all",
"telephone/us"
],
"financial_data": [
"credit_card_numbers",
"bank_account_number/ca",
"bank_account_number/uk",
"bank_account_number/all"
],
"government_id": [
"driving_license/americas"
],
"sensitive_data": [
"racial_ethnic_origin"
]
}
I have the following, which almost works:
import org.json.JSONObject;
...
final List<String> jsonStrings = ...; // A list of the above sample JSONs
final List<JSONObject> jsonObjects = jsonStrings
.stream()
.map(JSONObject::new)
// JSONObject.getNames() (called later on) will return null if JSONObject is empty, so filter out empty objects.
.filter(jsonObject -> !jsonObject.isEmpty())
.collect(Collectors.toList());
if (jsonObjects..size() > 1) {
// Merge multiple JSONObjects: https://stackoverflow.com/a/2403453/12177456
final JSONObject firstJsonObject = jsonObjects.get(0);
final JSONObject merged = new JSONObject(firstJsonObject, JSONObject.getNames(firstJsonObject));
final List<JSONObject> remainingJsonObjects = jsonObjects.subList(1, jsonObjects.size());
for (final JSONObject nextJsonObject : remainingJsonObjects) {
for (final String nextJsonObjectFieldName : JSONObject.getNames(nextJsonObject)) {
merged.put(nextJsonObjectFieldName, nextJsonObject.get(nextJsonObjectFieldName));
}
}
return merged;
}
however, where I would expect to see 4 entries in financial_data:
...
"financial_data": [
"bank_account_number/all",
"bank_account_number/uk",
"bank_account_number/ca",
"credit_card_numbers"
]
...
instead, I see just 3, with bank_account_number/uk not in the merged result:
...
"financial_data": [
"bank_account_number/all",
"bank_account_number/ca",
"credit_card_numbers"
]
...
I'm not stuck on using org.json, if it's simplier using gson, jackson, plain Java maps, I'm ok with that.
Actually, it won't work. The problem is here:
merged.put(nextJsonObjectFieldName, nextJsonObject.get(nextJsonObjectFieldName))
This replaces the entry with key nextJsonObjectFieldName with the later one. That is why you're getting in the financial_data from the second object.
{
"financial_data": [
"credit_card_numbers",
"bank_account_number/ca",
"bank_account_number/all"
]
}
You are seeing other keys okay because other keys hase exact same value in both JSON's. If you change the value of other keys too in the second json, you'll see it the merged JSON will have the values with the same key from second json. That is, IT WON'T WORK.
What you can do is, you can check if the key has already value in the map or not. If there's no existing JSONobject for this key, just put it into the merged as you're doing. Otherwise, we have some more job to do:
JSONObject jsonObject = merged.get(nextJsonObjectFieldName);
if (jsonObject != null) {
final JSONObject finalObj = mergeJsonObjectCheckingFieldValues(jsonObject, nextJsonObject.get(nextJsonObjectFieldName));
merged.put(nextJsonObjectFieldName, finalObj);
} else {
merged.put(nextJsonObjectFieldName, nextJsonObject.get(nextJsonObjectFieldName));
}
The mergeJsonObjectCheckingFieldValues method checks each element between the given two JSONObject and compares whether they are same. As per your example and for simply answering this question, I've assumed that each of the JSONObject is nothing but a list of String. For this, we'll be needing objectMapper. So make sure you have the com.fasterxml.jackson.databind.ObjectMapper in your project. So, the checking will be:
ObjectMapper mapper = new ObjectMapper();
public JSONObject mergeJsonObjectCheckingFieldValues(JSONObject jsonObject, JSONObject nextJsonObject)) {
List<String> existingList = Arrays.asList(mapper
.readValue(jsonObject.toString(), String[].class));
List<String> newList = Arrays.asList(mapper
.readValue(nextJsonObject.toString(), String[].class));
List<String> toBeAdded = newList
.stream()
.filter(x -> !existingList.contains(x))
.collect(Collectors.toList());
if(toBeAdded.size() > 0) {
existingList.addAll(toBeAdded);
}
return new JSONObject(JSONArray.toJSONString(existingList));
}
This is the probable solution to your problem. I haven't tested it, but the code should be pretty much this.
I went with the accepted answer here using gson:
https://stackoverflow.com/a/34092374/12177456
Handles recursively merging JsonObjects
Handles conflicts when the key exists in both maps
Has special handling for non-primitive values such as Arrays

How to replace keys in a map based on mapping

I have a JSON that I'm getting from some external system. I need to convert that JSON into key value based on my system mapping. For instance:
JSON from external system:
[{
"name": "Tim",
"address": "New York",
"education" : {
"university": "XYZ"
}
},
{
"name": "Steve",
"address": "UK"
}]
I have following mapping that we need to use:
{
"name": "firstName",
"address": "location",
"university": "college"
}
i.e name to be mapped to firstName and address to be mapped to location. And finally, my processed mapped will look like:
[{
"firstName": "Tim",
"location": "New York"
"education" : {
"college": "XYZ"
}
},
{
"firstName": "Steve",
"location": "UK"
}]
What can be the best way to achieve this? Should I use normal hashmap operations or is there any other efficient way. I was checking JSONNode for this purpose, but the approach was similar to hash map. Is there any utility I can use to traverse tree like json map and replace the key?
I'm a fan of Jackson which you can use to traverse the JSON. As you do so, populate a list of maps, using your system mapping to replace whatever keys are encountered that have a mapping, leaving the others as is. At the end, dump the list of maps back out as JSON.
Edit: adding code example below
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.IOException;
import java.util.*;
public class ReplaceKeys {
private static final ObjectMapper mapper = new ObjectMapper();
private static Map<String, String> keymap;
static {
try {
// Create the key map based on the json provided by OP
keymap = mapper.readValue("{\n" +
"\"name\": \"firstName\",\n" +
"\"address\": \"location\",\n" +
"\"university\": \"college\"\n" +
"}", Map.class);
} catch (IOException e) {
System.out.println("whoops");
}
}
public static String mapKeys(String input) throws IOException {
// Assume the input is an array and therefore so is the output.
List<Map<String, Object>> output = new ArrayList<>();
ArrayNode inputArray = (ArrayNode) mapper.readTree(input);
for (JsonNode node : inputArray) {
output.add(mapKeys(node));
}
return mapper.writeValueAsString(output);
}
private static Map<String, Object> mapKeys(JsonNode node) {
Map<String, Object> map = new HashMap<>();
for (Iterator<String> iterator = node.fieldNames(); iterator.hasNext(); ) {
String key = iterator.next();
key = keymap.containsKey(key) ? keymap.get(key) : key;
for (JsonNode child : node) {
if (node.isValueNode()) {
// This is coercing everything to a String. You could dig into using
// proper types based on node.getNodeType().
map.put(key, node.asText());
} else {
map.put(key, mapKeys(child));
}
}
}
return map;
}
}

Jackson - Get an entry inside array

I have the following JSON source:
{
"my-systems": [{
"SYSTEM_A": [{
"parameter-name": "a_param1",
"parameter-display-name": "parameter 1",
"optional": "true"
},
{
"parameter-name": "a_param2",
"parameter-display-name": "Parameter 2",
"optional": "false"
}
]
},
{
"SYSTEM_B": [{
"parameter-name": "b_param1",
"parameter-display-name": "Parameter 1",
"optional": "true"
},
{
"parameter-name": "b_param2",
"parameter-display-name": "Parameter 2",
"optional": "false"
}
]
}
]
}
I try to read it into a map of Map<String, SystemParameter[]>.
I have this code which I'm really not sure if it's the best approach for my goal.
ArrayNode systemsArr = (ArrayNode)jsonDoc.get("my-systems");
if(systemsArr!= null && !systemsArr.isEmpty()){
for(JsonNode systemNode : systemsArr ){
ObjectNode systemObj = (ObjectNode)systemNode;
System.out.println(systemObj .textValue());
}
}
Is it a valid approach? How do I get the name of the system (SYSTEM_A, SYSTEM_B) and convert the contained parameters into a parameters objects array?
You just need to use jackson-databind and jackson-annotations jar in your dependency and you should be able to run below code
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonParsing {
public static void main(String[] args) throws IOException {
String jsonFilePath = "src/main/resources/source.json"; // JSON File Path
MySystems mySystems = new ObjectMapper().readValue(new File(jsonFilePath),MySystems.class);
Map<String,SystemParameter[]> outputMap = new HashMap<>();
for (Map<String,List<SystemParameter>> map :mySystems.mySystems) {
for (String key :map.keySet()) {
outputMap.put(key, map.get(key).toArray(new SystemParameter[0]));
}
}
System.out.println(outputMap);
}
}
class MySystems {
#JsonProperty("my-systems")
List<Map<String,List<SystemParameter>>> mySystems;
}
class SystemParameter {
#JsonProperty("parameter-name")
String paramName;
#JsonProperty("parameter-display-name")
String paramDispName;
#JsonProperty("optional")
String optional;
}
Using an array 'my-systems' is of little use if all you're doing is keeping your keys unique. (I am assuming your SYSTEM_A may be different).
Instead, I suggest you format the JSON data in the following way:
{
"my-systems": [
{
"system-name" : {
"name":"System_A",
"parameters": [
{
"parameter-name": "a_param1",
"parameter-display-name": "parameter 1",
"optional": "true"
},
{
"parameter-name": "a_param2",
"parameter-display-name": "Parameter 2",
"optional": "false"
}
]
}
}
]
}
This method is clean, and allows you to catch the name of the system under the property 'system-name' and it's parameters are nested inside. You can simply declare a model and Jackson (or gson) will simply take care of everything.
If you'd rather parse the response separately or you have no control over the response, you can opt to go with your implementation but you do not need to convert to ObjectNode. You can use the samples below inside your for loop:
String f2Str = jsonNode.get("f2").asText();
double f2Dbl = jsonNode.get("f2").asDouble();
int f2Int = jsonNode.get("f2").asInt();
long f2Lng = jsonNode.get("f2").asLong();
where 'f2' is your key, and you can get the key using node.fieldNames().next() which is actually getting the property from an iterator.
You may also try the ones below, they seem better to handle.
JsonNode parent = ...;
for (Iterator<String> it = parent.fieldNames() ; it.hasNext() ; ) {
String field = it.next();
System.out.println(field + " => " + parent.get(field));
}
for (Iterator<Map.Entry<String,JsonNode>> it = parent.fields() ;
it.hasNext() ; ) {
Map.Entry<String,JsonNode> e = it.next();
System.out.println(e.getKey() + " => " + e.getValue());
}
The latest examples are taken from here. Hope this helps.

Extracting data from JSON array

I know its an array, but I am completely new to JSON and need help comprehending how this is structured, here is my attempt at extracting data:
String JSonString = readURL("//my URL is here");
JSONArray s = JSONArray.fromObject(JSonString);
JSONObject Data =(JSONObject)(s.getJSONObject(0));
System.out.println(Data.get("name"));
My JSON data that I have goes like this :
{
"sports": [
{
"name": "basketball",
"id": 40,
"uid": "s:40",
"leagues": [
{
"name": "National Basketball Assoc.",
"abbreviation": "nba",
"id": 46,
"uid": "s:40~l:46",
"groupId": 7,
"shortName": "NBA",
"athletes": []
}
]
}
],
"resultsOffset": 10,
"resultsLimit": 10,
"resultsCount": 1,
"timestamp": "2013-11-18T03:15:43Z",
"status": "success"
}
I dont really have a strong grasp of this stuff so all the help is appreciated.
Here is the idea :
JSONObject root = new JSONObject(yourJsonString);
JSONArray sportsArray = root.getJSONArray("sports");
// now get the first element:
JSONObject firstSport = sportsArray.getJSONObject(0);
// and details of the first element
String name = firstSport.getString("name"); // basketball
int id = firstSport.getInt("id"); // 40
JSONArray leaguesArray = firstSport.getJSONArray("leagues");
// and so on, you can process leaguesArray similarly
It should work (feel free to complain about compile errors if there are any)
Your JSON data is an object (it starts with a curly brace). In the next inner layer, there is a single array (at key "sports"):
String jsonString = readURL("//my URL is here");
JSONObject result = JSONObject(jsonString);
JSONArray sports = result.getJSONArray("sports");
JSONObject sport = sport.getJSONObject(0);
System.out.println(sport.getString("name"));
I might have used another JSON library than you.
JSON means JavaScript Object Notation.
Objects in javascripts are just containers and can be represented by key-value pairs. Please find below notations to understand about json.
Represent objects in json: E.g. Student
{"name" : "Robin", "rollnumber" : "1"}
Represent array in json : E.g. Array of students
[{"name" : "Robin", "rollnumber" : "1"}, {"name" : "Mark", "rollnumber" : "2"}]
You can understand more on JSON from diagrams on this link http://www.json.org/fatfree.html
There are various ways available to to convert JSON to javaobject and javaobject to JSON : One of them is http://wiki.fasterxml.com/JacksonInFiveMinutes
Adding detailed code here along with the imports .
If this helps.
import org.json.JSONException;
import org.json.JSONObject;
public class extractingJSON {
public static void main(String[] args) throws JSONException {
// TODO Auto-generated method stub
String jsonStr = "{\"name\":\"SK\",\"arr\":{\"a\":\"1\",\"b\":\"2\"},\"arrArray\":[{\"a\":\"1\",\"b\":\"2\"}]}";
JSONObject jsonObj = new JSONObject(jsonStr);
String name = jsonObj.getString("name");
System.out.println(name);
String first = jsonObj.getJSONObject("arr").getString("a");
System.out.println(first);
first = jsonObj.getJSONArray("arrArray").getJSONObject(0).getString("a");
System.out.println(first);
}
}

How to get data as an json array from a server and convert it in to java array to use in android application

Possible duplicate
How to parse a JSON and turn its values into an Array?
[
[
"sn1",
"Liquid_level",
"85"
],
[
"sn2",
"Liquid_level,Temperature",
"95"
],
[
"sn2",
"Liquid_level,Temperature",
"50"
],
[
"sn3",
"Liquid_level",
"85.7"
],
[
"sn4",
"Liquid_level",
"90"
],
[
"sn5",
"Volt_meter",
"4.5"
],
[
"sn6",
"Temperature",
"56"
],
[
"sn8",
"Liquid_level",
"30"
]
]
This is the data i want to get to a java array (to create a dynamic table to show data).
i can get a text value using this
String response = null;
try {
response = CustomHttpClient.executeHttpPost("http://test.tester.com/check.php", postParameters);
String res=response.toString();}
As from How to parse a JSON and turn its values into an Array?:
for your example:
{'profiles': [{'name':'john', 'age': 44}, {'name':'Alex','age':11}]}
you will have to do something of this effect:
JSONObject myjson = new JSONObject(the_json);
JSONArray the_json_array = myjson.getJSONArray("profiles");
this returns the array object.
Then iterating will be as follows:
int size = the_json_array.length();
ArrayList<JSONObject> arrays = new ArrayList<JSONObject>();
for (int i = 0; i < size; i++) {
JSONObject another_json_object = the_json_array.getJSONObject(i);
//Blah blah blah...
arrays.add(another_json_object);
}
//Finally
JSONObject[] jsons = new JSONObject[arrays.size()];
arrays.toArray(jsons);
//The end...
You will have to determine if the data is an array (simply checking
that charAt(0) starts with [ character).
Hope this helps.
Credits to https://stackoverflow.com/users/251173/the-elite-gentleman
first parse this json array and store in ArrayList
try
{
ArrayList<String> arl= new ArrayList<String>();
JSONObject jobj = new JSONObject(signedData);
JSONArray jroot = jobj.getJSONArray("xxxxx");
for(int i=0;i<jroot.length();i++)
{
JSONObject jElement = jroot.getJSONObject(i);
arl.add(jElement.getString("xxxxx"));
}
}
catch (Exception e)
{
Log.v("log", "Error parsing data " + e.toString());
}
and then using forloop store to string Array..
Your conversion of JSON to Java largely depends on which library you are using to perform the task. The other answers here use the org.json library, but most geeks will react violently over its usage because it's quite slow. The fastest library I know of is Jackson, but I personally prefer Google-GSON because it's fast enough and yet remains very easy to use.
Looking at your sample string, you seem to have an array of arrays of strings. In Gson, you want to think of them as a Collection of a Collection of Strings. Here's the sample code:
import java.lang.reflect.Type;
import java.util.Collection;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class Main {
public static void main(String[] args) {
// your sample JSON string, converted to a java string
String json = "[\n [\n \"sn1\",\n \"Liquid_level\",\n \"85\"\n ],\n [\n \"sn2\",\n \"Liquid_level,Temperature\",\n \"95\"\n ],\n [\n \"sn2\",\n \"Liquid_level,Temperature\",\n \"50\"\n ],\n [\n \"sn3\",\n \"Liquid_level\",\n \"85.7\"\n ],\n [\n \"sn4\",\n \"Liquid_level\",\n \"90\"\n ],\n [\n \"sn5\",\n \"Volt_meter\",\n \"4.5\"\n ],\n [\n \"sn6\",\n \"Temperature\",\n \"56\"\n ],\n [\n \"sn8\",\n \"Liquid_level\",\n \"30\"\n ]\n]";
// instantiate a Gson object
Gson gson = new Gson();
// define the type of object you want to use it in Java, which is a collection of a collection of strings
Type collectionType = new TypeToken<Collection<Collection<String>>>(){}.getType();
// happiness starts here
Collection<Collection<String>> stringArrays = gson.fromJson(json, collectionType);
// simply print out everything
for (Collection<String> collection : stringArrays) {
for (String s : collection) {
System.out.print(s + ", ");
}
System.out.println();
}
}
}
And the output:
sn1, Liquid_level, 85,
sn2, Liquid_level,Temperature, 95,
sn2, Liquid_level,Temperature, 50,
sn3, Liquid_level, 85.7,
sn4, Liquid_level, 90,
sn5, Volt_meter, 4.5,
sn6, Temperature, 56,
sn8, Liquid_level, 30,
This is taken from the Google-GSON user guide: https://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples

Categories

Resources