Converting xml of any structure to json with nested arrays - java

I have XML which can be of any structure like below. Therefore there is no POJO class for instantiation. As you can see I have nested arrays (in this case reservations is an array of two reservation and every reservation have simple elements and arrays of rooms - but that is only example - there may be more arrays and nested arrays).
<reservations>
<reservation>
<id>1318504</id>
<add_date>2020-12-10 12:48:09</add_date>
<rooms>
<room>
<id>28902</id>
<floor>2</floor>
</room>
<room>
<id>28903</id>
<floor>3</floor>
</room>
</rooms>
</reservation >
<reservation>
<id>1318501</id>
<add_date>2021-05-07 07:47:05</add_date>
<rooms>
<room>
<id>5</id>
<floor>25</floor>
</room>
<room>
<id>6</id>
</room>
</rooms>
</reservation>
</reservations>
I need to convert it to Json as:
{
"reservations":[
{
"id":"1318504",
"add_date":"2020-12-10 12:48:09",
"rooms":[
{
"id":"28902",
"floor":2
},
{
"id":"28903",
"floor":3
}
]
},
{
"id":"1318501",
"add_date":"2021-05-07 07:47:05",
"rooms":[
{
"id":"5",
"floor":25
},
{
"id":"6"
}
]
}
]
}
I have read lots of topic about converting XML to Json. I tried something like:
json.org
JSONObject xmlJSONObj = XML.toJSONObject(xmlString);
jackson
JsonNode node = new XmlMapper().readTree(xmlContent);
underscore-java
String jsonString = U.xmlToJson(xmlContent)
and so on. Bu the result, in best case is like:
{
"reservations":{
"reservation":[
{
"rooms":{
"room":[
{
"id":28902,
"floor":2
},
{
"id":28903,
"floor":3
}
]
},
"add_date":"2020-12-10 12:48:09",
"id":1318504
},
{
"rooms":{
"room":[
{
"id":5,
"floor":25
},
{
"id":6
}
]
},
"add_date":"2021-05-07 07:47:05",
"id":1318501
}
]
}
}
I don't need nodes like reservation and room. Could you help me how can I solve this problem? I can manipulate with xml or json, but the form without these nodes is my target.

The solution:
import com.github.underscore.U;
String xml = "<reservations>\n"
+ " <reservation>\n"
+ " <id>1318504</id>\n"
+ " <add_date>2020-12-10 12:48:09</add_date>\n"
+ " <rooms> \n"
+ " <room>\n"
+ " <id>28902</id>\n"
+ " <floor>2</floor>\n"
+ " </room> \n"
+ " <room>\n"
+ " <id>28903</id>\n"
+ " <floor>3</floor>\n"
+ " </room>\n"
+ " </rooms>\n"
+ " </reservation >\n"
+ " <reservation>\n"
+ " <id>1318501</id>\n"
+ " <add_date>2021-05-07 07:47:05</add_date>\n"
+ " <rooms>\n"
+ " <room>\n"
+ " <id>5</id>\n"
+ " <floor>25</floor>\n"
+ " </room>\n"
+ " <room>\n"
+ " <id>6</id>\n"
+ " </room>\n"
+ " </rooms>\n"
+ " </reservation>\n"
+ "</reservations>";
Map<String, Object> map = U.fromXmlMap(xml);
U.set(map, "reservations", U.get(map, "reservations.reservation"));
List<Map<String, Object>> list = U.get(map, "reservations");
for (Map<String, Object> item : list) {
U.set(item, "rooms", U.get(item, "rooms.room"));
}
System.out.println(U.toJson(map));
Result:
{
"reservations": [
{
"id": "1318504",
"add_date": "2020-12-10 12:48:09",
"rooms": [
{
"id": "28902",
"floor": "2"
},
{
"id": "28903",
"floor": "3"
}
]
},
{
"id": "1318501",
"add_date": "2021-05-07 07:47:05",
"rooms": [
{
"id": "5",
"floor": "25"
},
{
"id": "6"
}
]
}
],
"#omit-xml-declaration": "yes"
}

You may be able to use json:Array="true" in the array - and the JsonConvert will interpret it correctly.
https://www.newtonsoft.com/json/help/html/ConvertXmlToJsonForceArray.htm

Related

Apply some condition on jsonnode and filter resultset in Java

I have an array of Jsonnodes. something like that
[
{
"coupon": "VAR",
"currency": "USD",
"sip": "94989WAX5",
"lastModifiedDate": "2022-09-23T08:16:25Z"
},
{
"coupon": "VAR1",
"currency": "USD",
"sip": "94989WAX5",
"lastModifiedDate": "2022-09-21T08:16:25Z"
},
{
"coupon": "VAR3",
"currency": "USD",
"sip": "XHBRYWEB1",
"lastModifiedDate": "2022-09-20T08:16:25Z"
}
]
I have a requirement, if the sip value of two nodes are same then I need to pick only that sip which lastModifiedDate is latest. In above example the final output should be remaining two nodes.
[
{
"coupon": "VAR",
"currency": "USD",
"sip": "94989WAX5",
"lastModifiedDate": "2022-09-23T08:16:25Z"
},
{
"coupon": "VAR3",
"currency": "USD",
"sip": "XHBRYWEB1",
"lastModifiedDate": "2022-09-20T08:16:25Z"
}
]
I was try to solve it by creating HashMap<String,JsonNode> where Sip is the key and the JsonNode is complete node. It doesn't seems to be a cleaner way. is there any other way to achieve it. I am using fasterxml.jackson.databind.JsonNode
Map<String, JsonNode> map =
jsonNodeList.stream()
.collect(
toMap(
jsonNode -> jsonNode.get("sip").asText(),
jsonNode -> jsonNode,
(jsonNode1, jsonNode2) -> {
boolean after =
LocalDateTime.parse(String.valueOf(jsonNode1.get("lastModifiedDate")))
.isAfter(
LocalDateTime.parse(
String.valueOf(jsonNode2.get("lastModifiedDate"))));
return after ? jsonNode1 : jsonNode2;
},
HashMap::new));
https://github.com/octomix/josson
Deserialization
Josson josson = Josson.fromJsonString(
"[" +
" {" +
" \"coupon\": \"VAR\"," +
" \"currency\": \"USD\"," +
" \"sip\": \"94989WAX5\"," +
" \"lastModifiedDate\": \"2022-09-23T08:16:25Z\"" +
" }," +
" {" +
" \"coupon\": \"VAR1\"," +
" \"currency\": \"USD\"," +
" \"sip\": \"94989WAX5\"," +
" \"lastModifiedDate\": \"2022-09-21T08:16:25Z\"" +
" }," +
" {" +
" \"coupon\": \"VAR3\"," +
" \"currency\": \"USD\"," +
" \"sip\": \"XHBRYWEB1\"," +
" \"lastModifiedDate\": \"2022-09-20T08:16:25Z\"" +
" }" +
" ]");
Transformation
JsonNode node = josson.getNode("group(sip)#.elements.findByMax(lastModifiedDate)");
System.out.println(node.toPrettyString());
Output
[ {
"coupon" : "VAR",
"currency" : "USD",
"sip" : "94989WAX5",
"lastModifiedDate" : "2022-09-23T08:16:25Z"
}, {
"coupon" : "VAR3",
"currency" : "USD",
"sip" : "XHBRYWEB1",
"lastModifiedDate" : "2022-09-20T08:16:25Z"
} ]

How can I structurally modify a JsonObject and replace some of its values?

I have a json in a JsonObject such as:
"customer": {
"full_name": "John John",
"personal": {
"is_active": "1",
"identifier_info": {
"hobbies": [
"skiing",
"traveling"
],
"user_id": "1234",
"office_id": "2345"
}
}
}
Is there a way to modify the JsonObject so as to remove the hobbies completely from the identifier_info and leave the rest untouched and then add the contents of hobbies the same way as the others? i.e.
"customer": {
"full_name": "John John",
"personal": {
"is_active": "1",
"identifier_info": {
"skiing":"expert",
"traveling":"rarely",
"user_id": "1234",
"office_id": "2345"
}
}
}
Find the full implementation for removing the JSON Array "hobbies" and to insert them in the parent JSON Object directly.
public class ProcessJSONString {
String data ="{\"customer\": { \n" +
" \"full_name\": \"John John\", \n" +
" \"personal\": { \n" +
" \"is_active\": \"1\", \n" +
" \"identifier_info\": { \n" +
" \"hobbies\": [ \n" +
" \"skiing\",\n" +
" \"traveling\"\n" +
" ], \n" +
" \"user_id\": \"1234\", \n" +
" \"office_id\": \"2345\"\n" +
" } \n" +
" } \n" +
"}} ";
public void processData() {
try {
JSONObject result = new JSONObject(data);
JSONObject customer = result.getJSONObject("customer");
JSONObject personal = customer.getJSONObject("personal");
JSONObject identifierInfo =
personal.getJSONObject("identifier_info");
JSONArray hobbies = identifierInfo.getJSONArray("hobbies");
identifierInfo.remove("hobbies");
//Under the assumption the tags will be added by the user, the code has been inserted.
identifierInfo.put("skiing","expert");
identifierInfo.put("traveling","rarely");
} catch (JSONException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ProcessJSONString instance = new ProcessJSONString();
instance.processData();
}
}
That should be no problem, using JsonObject's remove() method. It returns the removed JsonElement. Assuming the original json is a JsonObject called customer:
JsonObject identifierInfo = customer.getAsJsonObject("personal").getAsJsonObject("identifier_info");
JsonArray hobbies = (JsonArray) identifierInfo.remove("hobbies");
after that you can just add the hobbies to the identifierInfo and get the desired result:
for (JsonElement aHobby : hobbies) {
identifierInfo.addProperty(aHobby.getAsString(), "expert");
}
don't forget to add null checks as needed.

How to get level of each object in json where objects can have any number of children of same object type

I have an Employee level structure like below image
This structure is populated and stored with help of json like this
{
"name": "Lao Lao",
"title": "general manager",
"children": [
{
"name": "Bo Miao",
"title": "department manager",
"children": [
{
"name": "Li Jing",
"title": "senior engineer"
},
{
"name": "Li Xin",
"title": "senior engineer",
"children": [
{
"name": "To To",
"title": "engineer"
},
{
"name": "Fei Fei",
"title": "engineer"
},
{
"name": "Xuan Xuan",
"title": "engineer"
}
]
}
]
},
{
"name": "Su Miao",
"title": "department manager",
"children": [
{
"name": "Pang Pang",
"title": "senior engineer"
},
{
"name": "Hei Hei",
"title": "senior engineer",
"children": [
{
"name": "Xiang Xiang",
"title": "UE engineer"
},
{
"name": "Dan Dan",
"title": "engineer"
},
{
"name": "Zai Zai",
"title": "engineer"
}
]
}
]
}
]
}
I want to parse this Json to get all the objects with the level and parent name like this
{name = Lao lao , parent = null , level = 1 }
{name = Bao Miao , parent = Lao lao , level = 2 }
..................................................
{name = Li Jing , parent = Bao Miao , level = 3 }
How can we parse this with help of java?If there is any library with such functionality, please let me know.
Implement Model definition as below. Also put level and parentName in Model class.
class Employee{
String name;
String title;
Employee children[];
int level;
String parentName;
#Override
public String toString(){
return "{name = "+name+" , parent = "+parentName+ ", level = "+level+ " }";
}
}
Parse the json data using GSON API.
Employee e= new Gson().fromJson(new JsonReader(new FileReader("file.json")), Employee.class);
This is complete program for you. Finally i was able to write all the code for you after spending an hour on this. Working fine so far :)
import java.io.FileReader;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
public class ParseJson {
public static void main(String a[]) {
Gson g = new Gson();
try {
Employee e = g.fromJson(new JsonReader(new FileReader("file.json")), Employee.class);
parseEmployees(e);
printEmployee(e);
} catch (Exception e1) {
e1.printStackTrace();
}
}
private static void parseEmployees(Employee e) {
setParentAndLevel(e, 1, null);
}
private static void setParentAndLevel(Employee e, int lvl, String parent) {
e.level = lvl;
e.parentName = parent;
if (e.children != null && e.children.length > 0) {
lvl++;
for (Employee emp : e.children) {
setParentAndLevel(emp, lvl, e.name);
}
}
}
public static void printEmployee(Employee e){
System.out.println(e);
if (e.children != null && e.children.length > 0) {
for (Employee emp : e.children) {
printEmployee(emp);
}
}else{
return ;
}
}
}
class Employee {
String name;
String title;
Employee children[];
int level;
String parentName;
#Override
public String toString() {
return "{name = " + name + " , parent = " + parentName + ", level = " + level + " }";
}
}
Output :
{name = Lao Lao , parent = null, level = 1 }
{name = Bo Miao , parent = Lao Lao, level = 2 }
{name = Li Jing , parent = Bo Miao, level = 3 }
{name = Li Xin , parent = Bo Miao, level = 3 }
{name = To To , parent = Li Xin, level = 4 }
{name = Fei Fei , parent = Li Xin, level = 4 }
{name = Xuan Xuan , parent = Li Xin, level = 4 }
{name = Su Miao , parent = Lao Lao, level = 2 }
{name = Pang Pang , parent = Su Miao, level = 3 }
{name = Hei Hei , parent = Su Miao, level = 3 }
{name = Xiang Xiang , parent = Hei Hei, level = 4 }
{name = Dan Dan , parent = Hei Hei, level = 4 }
{name = Zai Zai , parent = Hei Hei, level = 4 }
look like I have so much time and waste my time doing this for you because it sound challenging basically I turn this into a jsonObject first then I do a bfs graph walk to find the level and parent told you it is a graph problem again there is some bug on the level but I want the community or you to fix the bug yourself
EDIT: I have fix the level bug for you already again ask me if you have any question
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception{
String JSON_STRING = "{\n" +
" \"name\": \"Lao Lao\",\n" +
" \"title\": \"general manager\",\n" +
" \"children\": [\n" +
" {\n" +
" \"name\": \"Bao Miao\",\n" +
" \"title\": \"department manager\",\n" +
" \"children\": [\n" +
" {\n" +
" \"name\": \"Li Jing\",\n" +
" \"title\": \"senior engineer\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Li Xin\",\n" +
" \"title\": \"senior engineer\",\n" +
" \"children\": [\n" +
" {\n" +
" \"name\": \"To To\",\n" +
" \"title\": \"engineer\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Fei Fei\",\n" +
" \"title\": \"engineer\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Xuan Xuan\",\n" +
" \"title\": \"engineer\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"name\": \"Su Miao\",\n" +
" \"title\": \"department manager\",\n" +
" \"children\": [\n" +
" {\n" +
" \"name\": \"Pang Pang\",\n" +
" \"title\": \"senior engineer\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Hei Hei\",\n" +
" \"title\": \"senior engineer\",\n" +
" \"children\": [\n" +
" {\n" +
" \"name\": \"Xiang Xiang\",\n" +
" \"title\": \"UE engineer\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Dan Dan\",\n" +
" \"title\": \"engineer\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Zai Zai\",\n" +
" \"title\": \"engineer\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}] \n";
JSONObject obj = new JSONObject(JSON_STRING);
Deque<JSONObject> deque = new ArrayDeque<>();
Map<String, String> res = new HashMap<>();
int level = 1;
res.put("NULL", obj.getString("name")+ "-" + level);
deque.add(obj);
Map<String, Integer> levelmap = new HashMap<>();
levelmap.put(obj.getString("name"), 1);
while (!deque.isEmpty()){
JSONObject u = deque.poll();
try {
JSONArray children = u.getJSONArray("children");
for (int i = 0; i < children.length(); i++) {
deque.add(children.getJSONObject(i));
levelmap.put(children.getJSONObject(i).getString("name"), levelmap.get(u.getString("name")) + 1);
res.put(children.getJSONObject(i).getString("name"), u.getString("name") + "-" + levelmap.get(children.getJSONObject(i).getString("name")));
}
}catch (JSONException jex){
System.out.println("end of the tree");
}
}
//turn it back into a json array format
String str = new String("[]");
JSONArray jsonArray = new JSONArray(str);
System.out.println(res);
for(String key: res.keySet()){
String st = new String("{}");
JSONObject jsonObject = new JSONObject(st);
//key is parent
String[] tok = res.get(key).split("-");
String child = tok[0];
String mylevel = tok[1];
jsonObject.put("name", key);
jsonObject.put("level", mylevel);
jsonObject.put("parent", child);
jsonArray.put(jsonObject);
}
System.out.println(jsonArray.toString(2));
}
}
output:
[
{
"parent": "Hei Hei",
"level": "4",
"name": "Xiang Xiang"
},
{
"parent": "Lao Lao",
"level": "2",
"name": "Bao Miao"
},
{
"parent": "Lao Lao",
"level": "1",
"name": "NULL"
},
{
"parent": "Su Miao",
"level": "3",
"name": "Hei Hei"
},
{
"parent": "Hei Hei",
"level": "4",
"name": "Dan Dan"
},
{
"parent": "Hei Hei",
"level": "4",
"name": "Zai Zai"
},
{
"parent": "Li Xin",
"level": "4",
"name": "Xuan Xuan"
},
{
"parent": "Su Miao",
"level": "3",
"name": "Pang Pang"
},
{
"parent": "Li Xin",
"level": "4",
"name": "Fei Fei"
},
{
"parent": "Li Xin",
"level": "4",
"name": "To To"
},
{
"parent": "Bao Miao",
"level": "3",
"name": "Li Jing"
},
{
"parent": "Lao Lao",
"level": "2",
"name": "Su Miao"
},
{
"parent": "Bao Miao",
"level": "3",
"name": "Li Xin"
}
]
Yes, you can do this. First, you need to map this json to POJO.
So, Create a model class like this
class Employee{
String name;
String title;
List<Employee> Children;
}
If you can map this json to POJO. Then you only need to run through a loop to get what you want.

XMLSerializer missing tags

I have a big problem with XMLSerializer... I use JSON lib (net.sf.json) and this is my code:
public static void main(String[] args) throws Exception {
String xmlInputMsg = "<state>\n" +
" <appId>newID</appId>\n" +
" <newDocuments>\n" +
" <nameValues>\n" +
" <name>test1</name>\n" +
" <value>123456</value>\n" +
" </nameValues>\n" +
" <nameValues>\n" +
" <name>test2</name>\n" +
" <value>987654</value>\n" +
" </nameValues>\n" +
" </newDocuments>\n" +
" <oldDocument>\n" +
" <oldAppId>true</oldAppId>\n" +
" <name>App</name>\n" +
" <source>NA</source>\n" +
" </oldDocument>\n" +
"</state>";
String result = null;
XMLSerializer xmlSerializer = new XMLSerializer();
xmlSerializer.setForceTopLevelObject(true);
result = XMLSerializer.class.toGenericString();
System.out.println(result);
}
My current output is:
"state": {
"appId": "newID",
"newDocuments": [
{
"name": "test1",
"value": "123456"
},
{
"name": "test2",
"value": "987654"
}
],
"oldDocument": {
"oldAppId": "true",
"name": "App",
"source": "NA"
}
}}
But I would like have this msg:
{
"state": {
"appId": "newID",
"newDocuments": {
"nameValues": [
{
"name": "test1",
"value": "123456"
},
{
"name": "test2",
"value": "987654"
}
]
},
"oldDocument": {
"oldAppId": "true",
"name": "App",
"source": "NA"
}
}}
Unfortunately now I missing tag nameValues. Could someone help me with this?

how to use maxAggregation in jest elasticsearch

i want to get the maximun id form a subfield of an aptitude object,
{
"mappings": {
"aptitude": {
"dynamic": "strict",
"properties": {
"id": {
"type": "long"
},
"es": {
"type": "text"
},
"en": {
"type": "text"
},
"behaviors": {
"properties": {
"id": {
"type": "long"
},
"es": {
"type": "text"
},
"en": {
"type": "text"
}
}
}
}
}
}
as you can see the aptitude have an array of behaviors who in turn have an id, afaik i should use the maxAggregation from Jest, but cant find a decent example of how to do it in java, can someone help?
i found the way like this:
String query = "{\n"
+" \"query\" : {\n"
+" \"match\" : {\"id\":" + aptitudeId + "}\n"
+" },\n"
+" \"aggs\" : {\n"
+" \"max1\" : {\n"
+" \"max\" : {\n"
+" \"field\" : \"behaviors.id\"\n"
+" }\n"
+" }\n"
+" }\n"
+"}";
i was looking into the aggregation builders from jest but doing it via query was much easier.
the return looks like this:
Search search = new Search.Builder(query)
.addIndex(aptitudeIndexName)
.addType(aptitudeTypeName)
.build();
try {
SearchResult result = client.execute(search);
MaxAggregation max1 = result.getAggregations().getMaxAggregation("max1");
Double max = max1.getMax();
return max.longValue() + 1;//so it would add 1 to the current maximum id

Categories

Resources