How to validate JSON having multiple root elements - java

I am having a ccode, which bulids jsonfile in the below format.
{"swap":1,"si":11},{"system":1,host:"new"},{"Cpu":1}
If I validate this jsonfile data i get an error as:
Parse error on line 4:
...": 1, "si": 11},{ "system": 1,
---------------------^ Expecting 'EOF'
How to resolve this issue?

Wrap those jsonObjects in to an JsonArray while building. Then in java iterate through the jsonarray.

In jsonevery key is double quoted "key". Your jsonis missing double quotes at host key. Make sure you're writing a well-formed json.
{ "system": 1, "host": "new" }
^ ^

am not a expert in JSON but i think you want to change a JSON like array value
[{"swap":1,"si":11},{"system":1,host:"new"},{"Cpu":1}]
insted of
{"swap":1,"si":11},{"system":1,host:"new"},{"Cpu":1}

You can also use this custom function even if you have complex objects.
static getParsedJson(jsonString) {
const parsedJsonArr = [];
let tempStr = '';
let isObjStartFound = false;
for (let i = 0; i < jsonString.length; i += 1) {
if (isObjStartFound) {
tempStr += jsonString[i];
if (jsonString[i] === '}') {
try {
const obj = JSON.parse(tempStr);
parsedJsonArr.push(obj);
tempStr = '';
isObjStartFound = false;
} catch (err) {
// console.log("not a valid JSON object");
}
}
}
if (!isObjStartFound && jsonString[i] === '{') {
tempStr += jsonString[i];
isObjStartFound = true;
}
}
return parsedJsonArr;
}

Related

Convert JSON to different looking CSV in Java

I need to write a code which would convert JSON file to CSV. The problem is in a format that the CSV file should look like.
Input json:
{
"strings":{
"1level1":{
"1level2":{
"1label1":"1value1",
"1label2":"1value2"
}
},
"2level1":{
"2level2":{
"2level3":{
"2label1":"2value1"
},
"2label2":"2value2"
}
}
}
}
And this is expected csv file for this json:
Keys,Default
1level1.1level2.1label1,1value1
1level1.1level2.1label2,1value2
2level1.2level2.2level3.2label1,2value1
2level1.2level2.2label2,2value2
I was trying to go through JSON file using recursion but this didn't work for me because of rewriting JSON object on each iteration and code was working only till the first value. Are there any suggestions about how can it be done?
Note: have tried to use different JSON libraries, so for now can be used any of them
UPDATE #1:
Non-working code example I was trying to use to go through JSON tree:
public static void jsonToCsv() throws JSONException {
InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
JSONTokener jsonTokener = new JSONTokener(is);
JSONObject jsonObject = new JSONObject(jsonTokener);
stepInto(jsonObject);
}
private static void stepInto(JSONObject jsonObject) {
JSONObject object = jsonObject;
try {
Set < String > keySet = object.keySet();
for (String key: keySet) {
object = object.getJSONObject(key);
stepInto(object);
}
} catch (JSONException e) {
Set < String > keySet = object.keySet();
for (String key: keySet) {
System.out.println(object.get(key));
}
e.printStackTrace();
}
}
UPDATE #2:
Another issue is that I will never know the names of the JSON object and count of child objects (update JSON and CSV examples as well to make the image more clear). All that is known, that it will always start with strings object.
Library used:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
So found a solution by myself:
public static void jsonToCsv() throws JSONException, IOException {
InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
JSONTokener jsonTokener = new JSONTokener(is);
JSONObject jsonObject = new JSONObject(jsonTokener).getJSONObject("strings");
builder = new StringBuilder();
while (!jsonObject.isEmpty()) {
stepInto(jsonObject);
}
String[] lines = builder.toString().split("\n"); // builder lines are in reverse order from expected so this array is used to reverse them
FileWriter csvWriter = new FileWriter("src/main/resources/toCsv.csv");
csvWriter.append("Keys,Default (en_US)\n");
for (int i = lines.length - 1; i >= 0; i--) {
csvWriter.append(lines[i]).append("\n");
}
csvWriter.flush();
csvWriter.close();
}
private static void stepInto(JSONObject jsonObject) {
for (String key: jsonObject.keySet()) {
Object object = jsonObject.get(key);
if (object instanceof JSONObject) {
builder.append(key).append(".");
stepInto(jsonObject.getJSONObject(key));
} else {
builder.append(key).append(",").append(object).append("\n");
jsonObject.remove(key);
break;
}
if (jsonObject.getJSONObject(key).isEmpty()) {
jsonObject.remove(key);
}
break;
}
}
I think you just missed keeping track of your result, otherwise it looks good.
Let's say your result is a simple string. Then you have to concatenate all keys while traversing the json object until you reach a primitive value (like a number or a string).
(I am writing this out of my head, so please forgive me for incorrect syntax)
private static String stepInto(JSONObject jsonObject) { // we change "void" to "String" so we can record the results of each recursive "stepInto" call
//JSONObject object = jsonObject; // we don't need that. Both variables are the same object
String result ="";
try {
for (String key: jsonObject.keySet()) { // shorter version
Object object = jsonObject.get(key); // Attention! we get a simple Java Object
if(object instanceof JSONObject){
result+= key+"."+stepInto(jsonObject.getJSONObject(key)); // the recursive call, returning all keys concatenated to "level1.level2.level3" until we reach a primitive value
}
if(object instanceof JSONArray){
result+= key+", "+ ... // notice how we use the csv separator (comma) here, because we reached a value. For you to decide how you want to represent arrays
}
result+= key +", "+ object +"\n"; // here I am not sure. It may well be that you need to check if object is a String an Integer, Float or anything.
}
} catch (JSONException e) {
for (String key: jsonObject.keySet()) {
System.out.println(object.get(key));
}
e.printStackTrace();
result+= "\n"; // I added this fallback so your program can terminate even when an error occurs.
}
return result; // sorry, I forgot to accumulate all results and return them. So now we have only one actual "return" statement that will terminate the call and return all results.
}
As you can see, I didn't change much of your original method. The only difference is that now we keep track of the keys ("level1.level2...") for each recursive call.
EDIT
I added a +"\n"; so everytime we reach a value so we can terminate that "line".
AND more importantly, instead of returning everytime, I add the result of each call to a string, so we continue looping over the keys and concatenate all results. Each call of the method will return only once all keys are looped over. (sorry that missed that)
In your calling method you could print out the result, something like that:
JSONObject jsonObject = new JSONObject(jsonTokener);
String result = stepInto(jsonObject);
System.out.println(result);

How to parse json key value pair where one of the key having json value as a string

I have json as below as a response, where i have json as string in one of the key (i.e. SubSecData)
"CreatedTimestamp": "2019-10-26T11:28:06.732",
"FromBucket": "AVAILABLE",
"Country": "",
"Process": null,
"InfoId": "",
"ItemsShipped": 0,
"InventoryTypeId": "",
"ItemId": "ITEM02",
"ReasonCodeId": "",
"UpdatedBy": "admin#1",
"SubSecData": "{\"Spec\":\"ReceiptId\",\"Description\":\"Info for
Receipt\",\"Definition\":{\"Company\":\"***\",\"Season\":\"string\",\"SeasonYear\":\"string\",\"Style\":\"string\",\"StyleSuffix\":\"string\",\"Color\":\"string\",\"ColorSuffix\":\"string\",\"Dimension\":\"string\",\"Code\":\"string\",\"Description\":\"string\",\"ItemId\":\"ITEM02\",\"Description\":\"string\"},\"SubItemFields\":{\"TypeId\":\"\",\"ProcStatusId\":\"\",\"BatchNumber\":\"\",\"Attribute1\":\"\",\"Attribute2\":\"\",\"Attribute3\":\"\",\"InventoryAttribute4\":\"\",\"InventoryAttribute5\":\"\",\"CountryOfOrigin\":\"\",\"ExpirationDate\":\"***\",\"ManufactureDate\":\"***\",\"VendorId\":\"\"},\"InfoFields\":{\"FromBucket\":\"AVAILABLE\",\"ToBucket\":\"AVAILABLE\",\"AdjustmentQty\":\"1\",\"Quantity\":\"1\",\"AdjustmentType\":\"ADD\",\"AdjustedType\":\"ADD\",\"WeightedQty\":\"1.0\",\"WeightedType\":\"ADD\",\"InfoIncId\":\"GHJ686868585\",\"PpnType\":\"IPPN\",\"BWCId\":\"VABWC23969237\"},\"Variances\":{\"\":\"\",\"UnitsReceived\":\"\",\"ItemsShipped\":\"\",\"ItemsReceived\":\"\",\"ReceiptComplete\":\"\"}}",
"TransactionCode": "",
I need to read the data for SubSecData and print them as key, value pairs using java so that i can assert them with the expected key value pairs
I have tried below code and stuck and don't know how to proceed further
public validateNestedJson(expectedKeyValuePairs)
{
JSONObject getAPIJSONData= new JSONObject(getAPIResponse);
if (getAPIJSONData.get("SubSecData") != null)
{
log.info("Parsing Json Data");
//iterate expectedKeyValuePairs times
for(expectedKeyValuePairs=0; expectedKeyValuePairs.length; expectedKeyValuePairs++) {
//print all the SubSecData elements which match expected KeyValuePairs
getAPIJSONData.get("SubSecData").<k,v>toHashMap();
}
return true;
}
else
{
return false;
//print actualvalues - if one or more values doesn't match
}
}
I will call the "validateNestedJson" method as below
HashMap<String, String> expectedKeyValuePairs;
expectedKeyValuePairs.put("Description","String");
expectedKeyValuePairs.put("ItemId","ITEM02");
Boolean result = validateNestedJson (expectedKeyValuePairs);
Output should be true or false. If false, need to print the values which are false
SubSecData.Description = Array
SubSecData.ItemId = ITEM01
Finally, i was able to come up with a solution for the problem. Below is the code which i have used.
for (int i = 0; i< jsonArray.length(); i++) {
JSONObject jsonnew=jsonArray.getJSONObject(i);
HashMap<HashSet,Object> result = new ObjectMapper().readValue((DataInput) jsonnew, HashMap.class);
log.info(result.toString());
log.info(result);
try
{
for (Object key : expectedKeyValuePairs.keySet())
{
if (result.containsKey(key))
{
result.get(key).equals(expectedKeyValuePairs.get(key));
log.info("ExpectedKey" + key + "ExpectedValue" + expectedKeyValuePairs.get(key) + "ActualValue" + result.get(key));
}
}
}
catch (Exception e) {
//e.printStackTrace((PrintStream) key);
log.info("failed during wait" + e);
returnVal = false;
}
}
return returnVal;
}
Thanks all for the support.

How do I split a string by specific pairing groups?

I am writing my own JSON parser in Java and I am looking for a way to split a string by a comma or a colon, that are outside [], {} or "" pairs.
I found a tutorial via Google, and it works. The issue is, that it also captures the commas inside those brackets, and I need it to ommit them. I don't know how to edit the regular expression to exclude captured commass from one of these bracket pairs. I tried something like ",(?=([^\"\\{\\[]*\"[^\"\\}\\]]*\")*[^\"]*$)", but it doesn't work. It messes it up even more. The same also applies to the colon separation, which is used in separation of key and value of a JSON object.
Is there a way to combine the "", {} and [] pairs together in the regex in such way that it works? Sorry if I look like a lame, but I really can't figure out how the regex should look like.
BTW, this is a code snippet I want to use it in:
public class JavaJSON {
private HashMap<String, Object> content;
// Constructors
/**
* Create new empty JSON object
*/
public JavaJSON() {
this.content = new HashMap<>();
}
// ...
/**
* Parse a JSON string to a JSON object
*
* #param JSON JSON string to be converted to JSON object
* #return JSON object from given string
*/
public static JavaJSON parse(#NotNull String JSON) {
if (!JSON.startsWith("{") || !JSON.endsWith("}")) return null;
// If this is not a valid JSON string, return nothing.
JavaJSON output = new JavaJSON();
String content = JSON.substring(1, JSON.length() - 1);
if (content.length() == 0) return output; // if empty, return an empty JSON object
// Regex literals
String commaSeparated = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"; // TODO: Change commaSeparated to capture any {} [] "" pair group
String colonSeparated = ":(?=([^\"]*\"[^\"]*\")*[^\"]*$)"; // TODO: Change colonSeparated to capture any {} [] "" pair group
String[] tokens = content.split(commaSeparated);
if (tokens.length == 0) return null;
// Don't know exactly if this is going to happen, but better be sure
for (String token : tokens) {
String rawToken = token.trim();
if (rawToken.length() == 0) return null;
// Omitted comma, extra comma, etc. = JSON error
String[] mapToken = rawToken.split(colonSeparated);
if (mapToken.length < 2 || mapToken.length > 2) return null;
// Expected format = {"foo": "bar"}; format isn't valid
String mapKey = mapToken[0].trim();
String mapValue = mapToken[1].trim();
if (!mapKey.startsWith("\"") || !mapKey.endsWith("\"")) return null;
// Key must be a string
String rawMapKey = mapKey.substring(1, mapKey.length() - 1); // get quote-less variant
if (rawMapKey.length() == 0) return null;
// Key must not be empty
// check errors
if (mapValue.startsWith("{") && !mapValue.endsWith("}")) return null;
// Not a valid JSON object
if (mapValue.startsWith("[") && !mapValue.endsWith("]")) return null;
// Not a valid JSON array
if (mapValue.startsWith("\"") && !mapValue.endsWith("\"")) return null;
// Not a valid string
// get value object
Object rawMapValue;
// parse value object
if (mapValue.startsWith("\"") && mapValue.endsWith("\"")) {
rawMapValue = mapValue.substring(1, mapValue.length() - 1);
} else if (mapValue.startsWith("{") && mapValue.endsWith("}")) {
rawMapValue = parse(mapValue);
} else if (mapValue.startsWith("[") && mapValue.endsWith("]")) {
rawMapValue = parseArray(mapValue);
} else {
try {
rawMapValue = Long.parseLong(mapValue);
} catch (Exception e) {
try {
rawMapValue = Double.parseDouble(mapValue);
} catch (Exception f) {
return null;
// Not a valid number
}
}
}
output.update(rawMapKey, rawMapValue);
}
return output;
}
// ...
}

Efficient way of Searching in JSON Object in java

I have a list of JSON Objects as:
[{"name":"abc","id":"123"},{"name":"xyz","id":"345"}..] and a set of parameters like {"abc","def","xyz"}. I want to check whether the second set of parameters contains value that are not in name field of JSON Object in first array.
The algorithm I followed is:
Boolean flag = false;
for{name : nameSet} {
if(jsonObject.get("name")!=name{
flag = true;
}
}
if(flag){
System.out.print("not matched");
}
Are there any efficient way of doing it? Please suggest?
You are not checking each element with every element of Json array. You'll be needing an additional for loop for same.
Edit : Added the Json data to a key data. Refer the String json.
Boolean found = false, flag = false;
String json = "{ \"data\": [{"name":"abc","id":"123"},{"name":"xyz","id":"345"}]}"
JSONObject object = new JSONObject(json);
JSONObject getData = object.getJSONArray("data");
for{name : nameSet} {
found = false;
for(int i = 0; i < getData.size(); i++) {
JSONObject jsonObject = getData.getJSONObject(i);
if(jsonObject.get("name").equals(name)){
found= true;
break;
}
}
if(!found){
flag = true;
break;
}
}
if(flag){
System.out.print("not matched");
}

JSONArray Parsing error

I need help with parsing a JSON array.
[
{
"Header1": [
{
"path": "upload/images/1430572021716.jpg"
},
{
"path": "upload/images/1430574003703.jpg"
}
]
},
{
"Header2": [
{
"path": "upload/images/1430574124119.jpg"
},
{
"path": "upload/images/1430574203001.jpg"
}
]
}
]
I am receiving the above JSONArray perfectly. I want to iterate through the array and extract both the header text "Header1" and the value of path
I keep running into the following error message
at 0 of type org.json.jsonarray cannot be converted to jsonobject
after some research, this is due to the system not being able to parse to a JSON array. It does work if I change the "list" array to an objct, however this is not an array and i loose the ability to iterate through it.
Here is the code i tried to parse the array with
JSONArray mArray;
mArray = json;
//download json array
for (int i = 0; i < mArray.length(); i++) {
if(mArray != null) {
JSONArray list = mArray.getJSONArray(i);
if(list != null) {
for(int a = 0; a < list.length();a++) {
JSONObject elem = list.getJSONObject(a);
if (elem != null) {
listdata.add(elem.getString("path"));
}
}
}
}
}
You're trying to treat each element of the top-level array as another array - it's not, it's an object. That object then has another field whose value is an array. So you want something like:
for (int i = 0; i < json.length(); i++) {
JSONObject container = json.getJSONObject(i);
// We don't know the property name, but there's only one, apparently...
String key = container.keys().next();
JSONArray subarray = container.getJSONArray(key);
for (int j = 0; j < subarray.length(); j++) {
listdata.add(subarray.getJSONObject(j).getString("path"));
}
}
The second level of your JSON consists in your JSON array elements.
What you need, as you already mention, is to get them as JSONObject.
Then you getJSONArray from that object:
//download json array
for (int i = 0; i < mArray.length(); i++) {
if(mArray != null) {
JSONObject element = mArray.getJSONObject(i);
JSONArray list = element.getJSONArray("Header1");
if(list != null) {
However, since the "Header..." keys are changing, you might need to infer the key by invoking keys().
A much easier way for you to handle this would be to use GSON library and create POJO class to resemble ur JSON here is a nice website to do that
This works for JavaScript and very simple.
//mArray is your json array
let newArray = JSON.stringify(mArray);
mArray = JSON.parse(newArray);

Categories