I am currently studying newick format. https://en.wikipedia.org/wiki/Newick_format.
I have a newick string of a tree
(ABC,(STU,VWX)DEF,(GHI,JKL)MNO)PQR;
How to convert this string into a hierarchical JSON object like
JSONObject tree = {
name: 'PQR',
children: [{
name: 'ABC'
}, {
name: 'DEF',
children: [{
name: 'STU'
}, {
name: 'VWX'
}]
}, {
name: 'MNO',
children: [{
name: 'GHI'
}, {
name: 'JKL'
}]
}]
}
This is what i have tried but could not think further of how to fill the children of root node
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Series1 {
public static void main(String[] args) throws JSONException
{
String data="(ABC,(STU,VWX,EFG)DEF,YZA,HIJ,(GHI,JKL)MNO,BCD)PQR";
JSONObject tree=new JSONObject();
tree.put("name",data.substring(data.lastIndexOf(")")+1,data.length()));
tree.put("children", getChildren(data.substring(1,data.lastIndexOf(")"))));
}
public static JSONArray getChildren(String children) throws JSONException
{
JSONArray childrenArray=new JSONArray();
List<Integer> commaIndexList=new ArrayList<Integer>();
List<String> childrenStringList=new ArrayList<String>();
for (int index = children.indexOf(",");index >= 0;index = children.indexOf(",", index + 1))
{
if(children.substring(index+1, index+2).equalsIgnoreCase("("))
{
commaIndexList.add(index);
System.out.println(index);
}
}
childrenStringList.add(children.substring(0, commaIndexList.get(0)));
childrenStringList.add(children.substring(commaIndexList.get(commaIndexList.size()-1)+1));
for(int i=0;i<commaIndexList.size()-1;i++)
{
childrenStringList.add(children.substring(commaIndexList.get(i)+1, commaIndexList.get(i+1)));
}
for(String childrenString:childrenStringList)
{
JSONObject childObject=new JSONObject();
if(childrenString.lastIndexOf(")")>0)
{
childObject.put("name", childrenString.substring(childrenString.lastIndexOf(")")+1));
childObject.put("children", getChildren(childrenString.substring(childrenString.indexOf("(")+1,childrenString.lastIndexOf(")"))));
}
else
{
childObject.put("name",childrenString);
}
childrenArray.put(childObject);
}
return childrenArray;
}
}
I'd say this problem is similar to evaluating math expressions, e.g. 2+5*(10-3)=?
+
2 *
5 -
10 3
The key is to use stack operations to remake the 'inorder' tree structure into 'postorder' which is in this case 2 5 10 3 - * +
This is a definite form without parentheses and so easily readable for machine processing. If you are interested, i can have a look at it.
Related
I have 3 JSON payloads: A, B and C. I need to find out if payload A contains B and C.
When B is compared against A, I need the result to be true.
When C is compared against A, I need the result to be false
as college key does not exist in payload A.
Note: Below JSON payloads are just examples and can have different structure and values.
Payload A:
{
"id": "1",
"search": {
"name": "Testing",
"age": "25",
"school": "sacred heart"
},
"Address": {
"street": "Abcedf",
"road": "4th cross",
"city": "bangalore"
}
}
Payload B
{
"id": "1",
"search": {
"name": "Testing"
},
"Address": {
"street": "Abcedf",
"road": "4th cross"
}
}
Payload C
{
"id": "1",
"search": {
"name": "Testing",
"college": "global"
},
"Address": {
"street": "Abcedf",
"road": "4th cross"
}
}
First step would be to create Java objects from your Json. You can use Gson, Jackson or any other library of your choice. For this example I have used Gson.
Your class definition
private class JsonObject {
String id;
Map search;
#SerializedName(value="Address")
Map address;
// getter and setter
}
Parsing objects ( a,b and c are your Json Strings )
Gson gson = new Gson();
JsonObject objectA = gson.fromJson( a, JsonObject.class);
JsonObject objectB = gson.fromJson( b, JsonObject.class);
JsonObject objectC = gson.fromJson( c, JsonObject.class);
For the actual comparison there are many ways to accomplish what you need. One way would be to implement your own method for comparing the objects
private static boolean check( JsonObject firstObject, JsonObject secondObject ) {
return firstObject.getAddress().entrySet().containsAll( secondObject.getAddress().entrySet() )
&& firstObject.getSearch().entrySet().containsAll( secondObject.getSearch().entrySet() );
}
Call the method
System.out.println( check ( objectA, objectB ) );
System.out.println( check ( objectA, objectC ) );
Result
true
false
Your can, of course create your own logic to compare your Maps inside the objects. Take a look at Java Collections Framework or the Guava library which offers some handy utility methods for working with Collections.
You can utilise JsonPointer to implement contains method. A.contains(B) method returns true when object A contains all pointers which has object B and all values are the same. Two objects (A and B) are equal when A.contains(B) and B.contains(A). From definition: A.contains(A) returns true for every A.
Simple implementation could look like below:
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class JsonPointersApp {
public static void main(String[] args) throws IOException {
File aJsonFile = new File("./resource/a.json").getAbsoluteFile();
File bJsonFile = new File("./resource/b.json").getAbsoluteFile();
File cJsonFile = new File("./resource/c.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
JsonPayload payloadA = new JsonPayload(mapper.readTree(aJsonFile));
JsonPayload payloadB = new JsonPayload(mapper.readTree(bJsonFile));
JsonPayload payloadC = new JsonPayload(mapper.readTree(cJsonFile));
System.out.println("JSON A:" + payloadA);
System.out.println("JSON B:" + payloadB);
System.out.println("JSON C:" + payloadC);
System.out.println("A contains B:" + payloadA.contains(payloadB));
System.out.println("A contains C:" + payloadA.contains(payloadC));
System.out.println("B contains C:" + payloadB.contains(payloadC));
System.out.println("C contains B:" + payloadC.contains(payloadB));
System.out.println("A contains A:" + payloadA.contains(payloadA));
}
}
class JsonPayload {
private final JsonNode root;
private final List<JsonPointer> pointers = new ArrayList<>();
JsonPayload(JsonNode root) {
this.root = Objects.requireNonNull(root);
findPointers(this.root, "");
}
public boolean contains(JsonPayload other) {
//If number of pointers are different, JSON payloads are also different
if (this.pointers.size() < other.pointers.size()) {
return false;
}
// If pointers are not the same
if (!this.pointers.containsAll(other.pointers)) {
return false;
}
// check values
return other.pointers
.stream()
.allMatch(p -> this.root.at(p).equals(other.root.at(p)));
}
private void findPointers(JsonNode node, String path) {
if (node.isObject()) {
node.fields().forEachRemaining(entry -> findPointers(entry.getValue(), path + "/" + entry.getKey()));
} else if (node.isArray()) {
final int size = node.size();
for (int i = 0; i < size; i++) {
findPointers(node.get(i), path + "/" + i);
}
} else {
pointers.add(JsonPointer.compile(path));
}
}
#Override
public String toString() {
return pointers.toString();
}
}
Above code prints:
JSON A:[/id, /search/name, /search/age, /search/school, /Address/street, /Address/road, /Address/city]
JSON B:[/id, /search/name, /Address/street, /Address/road]
JSON C:[/id, /search/name, /search/college, /Address/street, /Address/road]
A contains B:true
A contains C:false
B contains C:false
C contains B:true
A contains A:true
import org.json.JSONObject;
import org.json.XML;
public class Example {
public static void main(String[] args) {
String xmlString = "<users><user name=test1 age=20></user><type><direct num=3></direct></type><report sub=eng score=30></report></users>";
JSONObject jsonObject = XML.toJSONObject(xmlString);
System.out.println(jsonObject);
}
}
I can remove elements after conversion from xml to json. But actually what i needed is that, the elements or attributes should be removed during conversion itself.
My required output is:
{
"users": {
"report": {
"score": 30
},
"type": {
"direct": {
"num": 3
}
},
"user": {
"age": 20
}
}
}
XML class does not provide methods to exclude tags. One possible solution is update the string to remove tags as below,
e.g to exclude type tag,
String splits[] = xmlString.split("(<\\/type>|<type>)");
xmlString = splits[0]+splits[2];
JSONObject jsonObject = XML.toJSONObject(xmlString);
System.out.println(jsonObject);
Output:
{"users":{"report":{"sub":"eng","score":30},"user":{"name":"test1","age":20}}}
To remove name element from user tag,
String xmlString = "<users><user name=test1 age=20></user><type><direct num=3></direct></type><report sub=eng score=30></report></users>";
//split by user tags
String splits[] = xmlString.split("(<\\/user>|<user )");
//remove name filed and combine other elements
String user1 = Arrays.stream(splits[1].split(" "))
.filter(s->!s.contains("name"))
.collect(Collectors.joining(" "));
//merge strings and user tag
xmlString = splits[0] + "<user " + user1 + "</user>" + splits[2];
JSONObject jsonObject = XML.toJSONObject(xmlString);
Output::
{
"users": {
"report": {
"sub": "eng",
"score": 30
},
"type": {
"direct": {
"num": 3
}
},
"user": {
"age": 20
}
}
}
UPDATE:
The best solution would be to remove from JsonObject,
jsonObject.getJSONObject("users").getJSONObject("user").remove("name")
org.json.XML package doesn't provide internal XML modifications. If you must use this, you have to make the necessary modifications in the json by yourself. Else you can preprocess the xml using java default xml parser, convert it to string and then convert it to json.
I have a JSON which has many arrays with a different name, just like below JSON.
{
"CA": [
{
"high": 5,
"low": 3,
"key": "ABPS"
},
{
"high": 6,
"low": 2,
"key": "ABPO"
}
],
"EE": [
{
"high": 8,
"low": 4,
"key": "ABPS"
},
{
"high": 7,
"low": 2,
"key": "ABPO"
}
]
}
I am trying to iterate JSON array values dynamically without specifying the name of the array.
I am able to read array with specifying the name of the array with below code but how to read array values dynamically without specifying the name of every array because the JSON file I have it has thousands of array.
package com.abc;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class JsonRead {
private static final String filePath = "jsonTestFile.json";
public static void main(String[] args) {
try (FileReader reader = new FileReader(ClassLoader.getSystemResource(filePath).getFile())) {
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
// get an array from the JSON object
JSONArray lang = (JSONArray) jsonObject.get("CA");
Iterator i = lang.iterator();
// take each value from the json array separately
while (i.hasNext()) {
JSONObject innerObj = (JSONObject) i.next();
System.out.println("high " + innerObj.get("high") + " low " + innerObj.get("low")+ " key " + innerObj.get("key"));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
This might help
for (Iterator iterator = jsonObject.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
JSONArray jArray = (JSONArray) jsonObject.get(key);
}
I have a json String like below and I want to split/explode it in to multiple json string.
input:
{
"name": "paddy",
"age": 29,
"cities": [
{
"cityName": "Chennai",
"year": "2013-2015"
},
{
"cityName": "Bangalore",
"year": "2015-2019"
}
]
}
And I want to convert in to two Json string
json 1
{
"name": "paddy",
"age": 29,
"cities": [
{
"cityName": "Chennai",
"year": "2013-2015"
}
]
}
json 2
{
"name": "paddy",
"age": 29,
"cities": [
{
"cityName": "Bangalore",
"year": "2015-2019"
}
]
}
As of now, my approach below using jackson library.
package com.test;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class JsonParser {
public static void main(String[] args) throws IOException {
String json =
"{\n"
+ "\t\"name\": \"paddy\",\n"
+ "\t\"age\": 29,\n"
+ "\t\"cities\": [\n"
+ "\t\t{\n"
+ "\t\t\t\"cityName\": \"Chennai\",\n"
+ "\t\t\t\"year\": \"2013-2015\"\n"
+ "\t\t},\n"
+ "\t\t{\n"
+ "\t\t\t\"cityName\": \"Bangalore\",\n"
+ "\t\t\t\"year\": \"2015-2019\"\n"
+ "\t\t}\n"
+ "\t]\n"
+ "}";
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// Create a list to store the result (the list will store Jackson tree model objects)
List<JsonNode> result = new ArrayList<>();
JsonNode tree = mapper.readTree(json);
JsonNode paths = tree.get("cities");
Iterator<JsonNode> elements = paths.elements();
while (elements.hasNext()) {
JsonNode path = elements.next();
// Create a copy of the tree
JsonNode copyOfTree = mapper.valueToTree(tree);
((ArrayNode)copyOfTree.get("cities")).removeAll().add(path);
// Add the modified tree to the result list
result.add(copyOfTree);
}
// Print the result
for (JsonNode node : result) {
System.out.println(mapper.writeValueAsString(node));
System.out.println();
}
}
}
This above approach can work fine if the json is smaller. Is there any better approach to handle large json files. For example, assume the "cities" have million objects.
Thanks.
There is many different factors you need to consider. First, do not copy the whole root object. In case, you have a big cities array you just waste a memory for creating new copy and remove all elements from it. See below example:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.File;
import java.io.IOException;
public class JsonApp {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./spring-basics/src/main/resources/test.json");
ObjectMapper mapper = new ObjectMapper();
// read whole JSON
ObjectNode root = (ObjectNode) mapper.readTree(jsonFile);
String citiesFieldName = "cities";
// remove cities from root, now it contains only common properties
ArrayNode cities = (ArrayNode) root.remove(citiesFieldName);
cities.elements().forEachRemaining(item -> {
// copy root
ObjectNode copyOfRoot = root.deepCopy();
// add one city to copy
copyOfRoot.set(citiesFieldName, copyOfRoot.arrayNode().add(item));
// add to result or send further
System.out.println(copyOfRoot);
});
}
}
Above code copies root and adds one element to cities array. Now, we need to think what to do with result. You can send it immediately for next processing or store in list and send it in bulk operation. Another improvement could be splitting cities arrays on bigger chunks, more than 1 element. See this article, how to split list. For example, in case you have 1_000_000 elements, split it on list of 1_000 elements chunks.
{
"items": [
{
"volumeInfo": {
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "0080509576"
},
{
"type": "ISBN_13",
"identifier": "9780080509570"
}
]
}
}
]
}
In the above json, I need to extract industryIdentifiers' identifier value without losing any digit.
I have tried using JSONArray but it eats up some of the digits
jsonObj.getJSONObject("items")
.getJSONObject("volumeInfo").getJSONArray("industryIdentifiers")
.getString(0);
Can anyone help me out?
Get the json array first and then iterate through it to parse.
Use org.json
import org.json.JSONArray;
import org.json.JSONObject;
JSONArray array = jsonObj.getJSONArray("items").getJSONObject(0).getJSONObject("volumeInfo")
.getJSONArray("industryIdentifiers");
for (int i = 0; i < array.length(); i++) {
String type = array.getJSONObject(i).getString("type");
String identifier = array.getJSONObject(i).getString("identifier");
System.out.println(type + " identifier : " + identifier);
}
Output on Java 9
ISBN_10 identifier : 0080509576
ISBN_13 identifier : 9780080509570