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");
}
Related
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);
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.
I am given three inputs .
A JSON object (nested)
A node structure
key value pair
My task is to append the key value pair to a node by looking at the node structure and updating the original JSON.
For example, if the inputs are,
JSON Object
{
a:
{
b:
{
c:{}
}
}
}
Node structure
a.b.
Key k and value v
The final updated JSON should look like
{
a:
{
b:
{
key:val
c:{}
}
}
}
Please note that the original JSON can be {} also. Then I have to build the whole JSON by looking at the node structure.
Here is my code
making a key value pair
public JSONObject makeEV(String ele, String val) throws JSONException{
JSONObject json =new JSONObject();
json.put(ele, val);
return json;
}
Appending it to JSON
public void modifiedJSON(JSONObject orgJson, String nodeStruct, JSONObject ev) throws JSONException{
JSONObject newJson = new JSONObject();
JSONObject copyJson = newJson;
char last = nodeStruct.charAt(nodeStruct.length()-1);
String lastNode = String.valueOf(last);
int i = 0;
while(orgJson.length() != 0 || i< nodeStruct.length()){
if(orgJson.length() ==0){
if(nodeStruct.charAt(i) == last){
newJson.put(String.valueOf(last), ev.toString());
}else{
newJson.put(String.valueOf(nodeStruct.charAt(i)), "");
}
newJson = newJson.getJSONObject(String.valueOf(nodeStruct.charAt(i)));
}
else if(i >= nodeStruct.length()){
if(orgJson.has(lastNode)){
newJson.put(String.valueOf(last), ev.toString());
}else{
}
}
}
}
I am stuck here. Please help. Thanks in advance.
It could be done using String#split(regex) as next:
public void modifiedJSON(JSONObject orgJson, String nodeStruct,
String targetKey, String value) {
// Split the keys using . as separator
String[] keys = nodeStruct.split("\\.");
// Used to navigate in the tree
// Initialized to the root object
JSONObject target = orgJson;
// Iterate over the list of keys from the first to the key before the last one
for (int i = 0; i < keys.length - 1; i++) {
String key = keys[i];
if (!target.has(key)) {
// The key doesn't exist yet so we create and add it automatically
target.put(key, new JSONObject());
}
// Get the JSONObject corresponding to the current key and use it
// as new target object
target = target.getJSONObject(key);
}
// Set the last key
target.put(targetKey, value);
}
I am looking to test if my json input contains a specific key with a specific value. I used org.joson lib to parse it and test it. I followed a recursive approach.
Is it the best approach to use? or is there a simpler one?
public boolean isJsonContains(String dataKey, String dataValue) {
logger.systemWriteOutput("is JSON data key "+ dataKey + " contains value: " +dataValue,3);
JSONObject jsonObject = null;
if (jsonInput!=null){
jsonObject = new JSONObject(jsonInput);
return isJSONObjectContainsKeyAndValue(dataKey, dataValue,jsonObject );
}
else{
return false;
}
}
private boolean isJSONObjectContainsKeyAndValue (String dataKey, String dataValue, JSONObject object){
String[] keys = JSONObject.getNames(object);
logger.systemWriteOutput("JSONObject is: "+object.toString(),3);
for (String key : keys)
{
boolean result = isJSONKeyContainsValue(key, dataValue, object);
if(result)
return true;
}
logger.systemWriteOutput("no value : "+ dataValue +" has been found for id: " +dataKey,3);
return false;
}
private boolean isJSONKeyContainsValue (String dataKey, String dataValue, JSONObject object){
Object value = object.get(dataKey);
if(dataKey.equals(dataKey) && value.toString().equals(dataValue)){
logger.systemWriteOutput("value of id: " +dataKey+" is: "+value.toString(),3);
return true;
}
else{
logger.systemWriteOutput("value of id: " +dataKey+" is: "+value.toString(),3);
//see if that the nested element contains the id
if (value instanceof JSONArray){
logger.systemWriteOutput("key array is: "+dataKey,3);
JSONArray jsonArray = (JSONArray) object.getJSONArray(dataKey);
logger.systemWriteOutput("key array lenbgth is: "+jsonArray.length(),3);
return isJSONArrayContainsKeyAndValue(dataKey,dataValue, jsonArray);
}
else if (value instanceof JSONObject){
return isJSONObjectContainsKeyAndValue(dataKey, dataValue, object.getJSONObject(dataKey));
}
}
return false;
}
private boolean isJSONArrayContainsKeyAndValue(String dataKey, String dataValue, JSONArray jsonArray) {
boolean result;
logger.systemWriteOutput("jsonArray is: "+jsonArray.toString(),3);
logger.systemWriteOutput("jsonArray length is: "+jsonArray.length(),3);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonobject = jsonArray.getJSONObject(i);
result= isJSONObjectContainsKeyAndValue(dataKey, dataValue ,jsonobject);
if( result)
return result;
}
return false;
}
Thanks in advance for your help!
The best way to parse JSON is to actually use an existing library, like GSON or JSON. For example, you could use the has method (doc) to find if a given key is present.
If you really want to build your own system, then an iterative approach will allow you to use add parallelism to your system. Other than that, it very usually depends on the problem and the implementation which one is "better". Check this lecture.
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;
}