replace multi-line string in java - java

Trying to replace multi line string in java using replaceAll method but it's not working. Is there anything wrong with below logic?
String content=" \"get\" : {\n" +
" \"name\" : [ \"Test\" ],\n" +
" \"description\" : \"Test description to replace\",\n" +
" \"details\" : \"Test details\"";
String searchString=" \"name\" : [ \"Test\" ],\n" +
" \"description\" : \"Test description to replace\",";
String replaceString=" \"name\" : [ \"Actual\" ],\n" +
" \"description\" : \"Replaced description\",";
Tried below options and none of them worked-
Pattern.compile(searchString, Pattern.MULTILINE).matcher(content).replaceAll(replaceString);
Pattern.compile(searchString, Pattern.DOTALL).matcher(content).replaceAll(replaceString);
content = content.replaceAll(searchString, replaceString);

DISCLAIMER: You should not use regex to manipulate JSON or XML that have infinite nested content. Finite automate are not adapted to manipulate those data structures and you should use a JSON/XML parser instead.
This being said, purely for learning purpose, I will quickly fix your code.
1) Use either replace instead of replaceAll to avoid that your searchString is interpreted as a regex:
String content=" \"get\" : {\n" +
" \"name\" : [ \"Test\" ],\n" +
" \"description\" : \"Test description to replace\",\n" +
" \"details\" : \"Test details\"";
String searchString=" \"name\" : [ \"Test\" ],\n" +
" \"description\" : \"Test description to replace\",";
String replaceString=" \"name\" : [ \"Actual\" ],\n" +
" \"description\" : \"Replaced description\",";
System.out.println(content.replace(searchString, replaceString));
output:
"get" : {
"name" : [ "Actual" ],
"description" : "Replaced description",
"details" : "Test details"
2) Or use replaceAll but escape the brackets to avoid them being interpreted as a character class definition attempt.
String searchString=" \"name\" : \\[ \"Test\" \\],\n" +
" \"description\" : \"Test description to replace\",";
String replaceString=" \"name\" : [ \"Actual\" ],\n" +
" \"description\" : \"Replaced description\",";
System.out.println(content.replaceAll(searchString, replaceString));
output:
"get" : {
"name" : [ "Actual" ],
"description" : "Replaced description",
"details" : "Test details"
Link: How to parse JSON in Java
You should load your json structure in an object
Change the values of the attributes of that object to the new values
Export it again in json format

Related

UpperCase all json keys using java and regex to find the matches

I'm beginner in java and have to replace all json Keys to upper Case .
My json can contain arrays (maybe nested Ones) and objects
Here is an example of my json input :
{
"transactionId": 181,
"Shipments": [
{
"shipmentId": 2,
"picklistId": "24RZ",
"ExtOrderId": "23-127",
"boxType": "120"
}
]
}
Here is an example of my json Output :
{
"TRANSACTIONID": 181,
"SHIPMENTS": [
{
"SHIPMENTID": 2,
"PICKLISTID": "24RZ",
"EXTORDERID": "23-127",
"BOXTYPE": "120"
}
]
}
I have tried to create an adapter but no chance to make it work correctly ,
Do i Have to use a regex and a replaceAll("everything before a : " , "upperCase()")
I'm reaching out to you guys to help me on this task because i could not find a way out to find a solution
One of the solutions is to flatten the JSON, upperCase() the keys and unflatten the JSON. Library Josson can do the transformation.
https://github.com/octomix/josson
Josson josson = Josson.fromJsonString(
"{" +
" \"transactionId\": 181," +
" \"Shipments\": [" +
" {" +
" \"shipmentId\": 2," +
" \"picklistId\": \"24RZ\"," +
" \"ExtOrderId\": \"23-127\"," +
" \"boxType\": \"120\"" +
" }" +
" ]" +
"}");
JsonNode node = josson.getNode(
"flatten('.').entries().map(key.upperCase()::value).mergeObjects().unflatten('.')");
System.out.println(node.toPrettyString());
Output
{
"TRANSACTIONID" : 181,
"SHIPMENTS" : [ {
"SHIPMENTID" : 2,
"PICKLISTID" : "24RZ",
"EXTORDERID" : "23-127",
"BOXTYPE" : "120"
} ]
}

Querying JSON Object in Java

Suppose my JSON is :
{
"Name" : "Anmol Jain",
"Address" : [
{
"type" : "home",
"category" : "primary",
"street" : "ABC"
},
{
"type" : "home",
"category" : "secondary",
"street" : "XYZ"
},
{
"type" : "work",
"category" : "primary",
"street" : "PQR"
}
]
}
I am designing a specific syntax for my project so that I can query the JSON.
For Example :
Address(type = home; category = secondary).street
this should give me result as "XYZ".
The first approach that comes to my mind is to parse the above code syntax, and look for conditions like type and category (by string parsing).
then loop through Address array and try to match those conditions. But this will give higher time complexity in case of large JSONs.
Is there any library which does that. Or if anyone can suggest me better approach. The syntax for the condition is flexible and I can mould it accordingly.
Thanks in advance.
For example, use library "Josson & Jossons"
https://github.com/octomix/josson
implementation 'com.octomix.josson:josson:1.3.22'
------------------------------------------------
Josson josson = Josson.fromJsonString(
"{" +
" \"Name\" : \"Anmol Jain\"," +
" \"Address\" : [" +
" {" +
" \"type\" : \"home\"," +
" \"category\" : \"primary\"," +
" \"street\" : \"ABC\"" +
" }," +
" {" +
" \"type\" : \"home\"," +
" \"category\" : \"secondary\"," +
" \"street\" : \"XYZ\"" +
" }," +
" {" +
" \"type\" : \"work\"," +
" \"category\" : \"primary\"," +
" \"street\" : \"PQR\"" +
" }" +
" ]" +
"}");
String street = josson.getString("Address[type='home' & category='secondary'].street");
Besides #tgdavies mentioned, also have a look at https://github.com/eiiches/jackson-jq, it uses the same syntax of jq, but in java implementation.

Transform JSON and create new one

I'm working with JSON in Java, and I want to trasnform a JSON I have as entry :
{
"index":{
"mutlipleIndices":[
{
"index":"languages",
"values":[
"English",
"German"
]
},
{
"index":"editors",
"values":[
"AC. Renus",
"Lodiga"
]
}
],
"simpleIndices":[
{
"index":"bookName",
"values":"A song Of Ice and fire"
},
{
"index":"nbPages",
"valeurs":1600
}
]
}
}
int this :
{
"data": { ... Put here the entry JSON ... },
"flatData": [
{
"key": "languages",
"type": "string",
"key_type": "languages.string",
"value_string": ["English", "German"]
},
{
"key": "editors",
"type": "string",
"key_type": "editors.string",
"value_string": ["AC. Renus", "Lodiga"]
},
{
"key": "bookName",
"type": "string",
"key_type": "bookName.string",
"value_string": "A song Of Ice and fire"
},
{
"key": "nbPages",
"type": "float",
"key_type": "nbPages.float",
"value_float": 1600
}
]
}
My entry JSON is a JsonNode (Jackson library), how can I iterate on that object and create a new one ?
Basically what I thought I'd do is iternate on the entry json, find an entry and transform it
Thanks in advance
Create 2 pojos
Mapping the input json (let's call it MyJsonInput.java)
Mapping the output you want (let's call it MyOutputObject.java).
These 2 classes should have fields which matches the json structure.
Create a mapper:
ObjectMapper objectMapper = new ObjectMapper();
Read the json and translate it into your object:
MyJsonInput myInput = objectMapper.readValue(json, MyJsonInput.class); //where json is a string with the content of your json file.
Now you have a MyJsonInput instance (myInput) containing the json data and you can do your logic to flatten it and fill your MyOutputObject.
To get the json string of MyOutputObject instance use:
String outputAsString = objectMapper.writeValueAsString(myOutputObject);
You can also threat your both input and output as a generic Map<String,Object> but in my opinion not the best way because it can get very complicated reading and parsing maps containing other maps, and not to mention that you need to cast your data into the appropriate type (string, number etc..)
https://github.com/octomix/josson
https://mvnrepository.com/artifact/com.octomix.josson/josson
implementation 'com.octomix.josson:josson:1.3.21'
-------------------------------------------------
Jossons jossons = new Jossons();
jossons.putDataset("input", Josson.fromJsonString(
"{\n" +
" \"index\":{\n" +
" \"multipleIndices\":[\n" +
" {\n" +
" \"index\":\"languages\",\n" +
" \"values\":[\n" +
" \"English\",\n" +
" \"German\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"index\":\"editors\",\n" +
" \"values\":[\n" +
" \"AC. Renus\",\n" +
" \"Lodiga\"\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"simpleIndices\":[\n" +
" {\n" +
" \"index\":\"bookName\",\n" +
" \"values\":\"A song Of Ice and fire\"\n" +
" },\n" +
" {\n" +
" \"index\":\"nbPages\",\n" +
" \"values\":1600\n" +
" }\n" +
" ]\n" +
" }\n" +
"}"));
Map<String, String> dictionaryFinder = new HashMap<>();
// Define a dictionary function, $0 is the function parameter.
dictionaryFinder.put("flatIndices()",
"$0->map(" +
"key:index," +
"type:if(values.isArray(),values[0],values).if(isText(),'string','float')," +
"key_type:concat(index,'.',if(values.isArray(),values[0],values).if(isText(),'string','float'))," +
"value_string:values)");
// Define a left concatenate operation to combine two arrays.
dictionaryFinder.put("allIndices",
"flatIndices(input->index.multipleIndices) <+< flatIndices(input->index.simpleIndices)");
ResolverProgress progress = new ResolverProgress("\nProgress:");
// The query is a left concatenate operation to combine two objects.
JsonNode output = jossons.evaluateQueryWithResolver(
"input->toObject('data') <+< allIndices->toObject('flatData')",
dictionaryFinder::get, null, progress);
// Print result.
System.out.println(output == null ? null : output.toPrettyString());
// Print resolution progress.
System.out.println(String.join("\n", progress.getSteps()));
Output
{
"data" : {
"index" : {
"multipleIndices" : [ {
"index" : "languages",
"values" : [ "English", "German" ]
}, {
"index" : "editors",
"values" : [ "AC. Renus", "Lodiga" ]
} ],
"simpleIndices" : [ {
"index" : "bookName",
"values" : "A song Of Ice and fire"
}, {
"index" : "nbPages",
"values" : 1600
} ]
}
},
"flatData" : [ {
"key" : "languages",
"type" : "string",
"key_type" : "languages.string",
"value_string" : [ "English", "German" ]
}, {
"key" : "editors",
"type" : "string",
"key_type" : "editors.string",
"value_string" : [ "AC. Renus", "Lodiga" ]
}, {
"key" : "bookName",
"type" : "string",
"key_type" : "bookName.string",
"value_string" : "A song Of Ice and fire"
}, {
"key" : "nbPages",
"type" : "float",
"key_type" : "nbPages.float",
"value_string" : 1600
} ]
}
Progress:
Round 1 : Resolving allIndices from flatIndices(input->index.multipleIndices) <+< flatIndices(input->index.simpleIndices)
Round 1 : Resolving flatIndices(input->index.multipleIndices) from $0->map(key:index,type:if(values.isArray(),values[0],values).if(isText(),'string','float'),key_type:concat(index,'.',if(values.isArray(),values[0],values).if(isText(),'string','float')),value_string:values)
Round 1 : Resolved flatIndices(input->index.multipleIndices) = Array with 2 elements
Round 2 : Resolving flatIndices(input->index.simpleIndices) from $0->map(key:index,type:if(values.isArray(),values[0],values).if(isText(),'string','float'),key_type:concat(index,'.',if(values.isArray(),values[0],values).if(isText(),'string','float')),value_string:values)
Round 2 : Resolved flatIndices(input->index.simpleIndices) = Array with 2 elements
Round 3 : Resolved allIndices = Array with 4 elements
Round 4 : Resolved query result = Object with 2 elements

Regex to match key value pairs from JSON

I need to match all the key values pairs from a complex JSON, but only values that are text / String.
For example from:
{"results":[
{"id":16,"name":"some name1","location":"some location1","parent":true, ,"region":"some region"},
{"id":157,"name":"some name2" , "location":some location2","parent":true}
],"totalCount":170}
I need to match:
"name"
"some name1"
"location"
"some location1"
"region"
"some region1"
etc
I have this [^:]+\"(?=[,}\s]|$) , but it only matches the values (which are correct).
I need also to match the keys: "name" , "location", "region" (and there can be other key names)
Here is an example for values matched https://regex101.com/r/m8FePZ/6
As others pointed out, if you want a robust solution use a JSON parser in your language.
If you want to use regex, and the engine supports lookbehind you can use this:
/("[^"]*"(?=:")|(?<=":)"[^"]*")/g
Explanation:
| - or combination of:
"[^"]*"(?=:") - quote, 0+ non-quotes, quote, followed by positive lookahead for colon and quote
(?<=":)"[^"]*" - positive lookbehind for quote and colon, followed by quote, 0+ non-quotes, quote
If you want to exclude the quotes in the matches, use this regex:
/(?<=")([^"]*(?=":")|(?<=":")[^"]*)/g
Note that these regexes fail for cover corner cases, such as whitespace around keys and values, escaped quotes in values, etc. Hence it is safer to use an actual JSON parser.
I saw that you decided not to use regex and used JSON library finally. Here is the simple solution by "Josson & Jossons".
https://github.com/octomix/josson
implementation 'com.octomix.josson:josson:1.3.22'
---------------------------------------------
Josson josson = Josson.fromJsonString(
"{\n" +
" \"results\": [\n" +
" {\n" +
" \"id\": 16,\n" +
" \"name\": \"some name1\",\n" +
" \"location\": \"some location1\",\n" +
" \"parent\": true,\n" +
" \"region\": \"some region\"\n" +
" },\n" +
" {\n" +
" \"id\": 157,\n" +
" \"name\": \"some name2\",\n" +
" \"location\": \"some location2\",\n" +
" \"parent\": true\n" +
" }\n" +
" ],\n" +
" \"totalCount\": 170\n" +
"}");
JsonNode node = josson.getNode(
"results.entries().[value.isText()]*.toArray()");
System.out.println(node.toPrettyString());
Output
[ "name", "some name1", "location", "some location1", "region", "some region", "name", "some name2", "location", "some location2" ]

Android - Parse JSON using GSON

I would like to parse data from JSON which is String type. I am using Google Gson. I'm wondering how can I get "OriginalTerm" and "FirstTranslation" information of this Json String:
{
"term0" : {
"PrincipalTranslations" : {
"0" :{
"OriginalTerm" : { "term" : "cat", "POS" : "n", "sense" : "domestic animal", "usage" : ""},
"FirstTranslation" : {"term" : "gato", "POS" : "nm", "sense" : " "}, "Note" : ""},
"1" :{
"OriginalTerm" : { "term" : "cat", "POS" : "n", "sense" : "member of cat family", "usage" : ""},
"FirstTranslation" : {"term" : "felino", "POS" : "nm", "sense" : "familia de animales"}, "Note" : ""}},
"AdditionalTranslations" : {
"0" :{
"OriginalTerm" : { "term" : "cat", "POS" : "n", "sense" : "guy", "usage" : "slang"},
"FirstTranslation" : {"term" : "tío, tipo, chaval", "POS" : "nm", "sense" : "coloq"},
"SecondTranslation" : {"term" : "vato", "POS" : "", "sense" : "Mex"}, "Note" : ""},
"original" : {
"Compounds" : {
"0" :{
"OriginalTerm" : { "term" : "alley cat", "POS" : "n", "sense" : "stray cat", "usage" : ""},
"FirstTranslation" : {"term" : "gato callejero", "POS" : "nm", "sense" : ""}, "Note" : ""},
"Lines" : "End Reached", "END" : true
}
I tried following these information but I can't solve it:
http://albertattard.blogspot.com.es/2009/06/practical-example-of-gson.html
JSON parsing using Gson for Java
I tried to serialized using GSON using POJO but I can't find the right structure, I tried using JsonObject too, jumping through object keys like "term0","PrincipalTranslations" but I have some trouble when I've multiple results for the same key, for example:
"0" :{
"OriginalTerm"....
"FirstTranslation"...
"1" :{
"OriginalTerm"....
"FirstTranslation"...
}
Thank you for advance.
Parsing a JSON with Gson can be done using a POJO that maps one-to-one your JSON text with your object. But, since you need only part of the JSON string, you can take advantage of JsonParser object that allows you to get a portion only of your JSON.
So you can get PrincipalTranslation part and then apply the POJO strategy keeping in mind that you have at least two structures: your Term and a composition of two Terms and a note (that I called Item).
Keep in mind that POJO I write are not following Java naming convention, so you can add an annotation to use a different member variable name.
Here's a code you can paste and run in you IDE to try.
package stackoverflow.questions;
import java.lang.reflect.Type;
import java.util.*;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
public class Q20337652 {
public static class Term {
String term;
String POS;
String sense;
String usage;
#Override
public String toString() {
return "Term [term=" + term + ", POS=" + POS + ", sense=" + sense + ", usage=" + usage + "]";
}
}
public static class Item {
Term OriginalTerm;
Term FirstTranslation;
String Note;
#Override
public String toString() {
return "Item [OriginalTerm=" + OriginalTerm + ", FirstTranslation=" + FirstTranslation + ", Note=" + Note + "]";
}
}
public static void main(String[] args){
String json =
" { "+
" "+
" \"term0\" : { "+
" \"PrincipalTranslations\" : { "+
" \"0\" :{ "+
" \"OriginalTerm\" : { \"term\" : \"cat\", \"POS\" : \"n\", \"sense\" : \"domestic animal\", \"usage\" : \"\"}, "+
" \"FirstTranslation\" : {\"term\" : \"gato\", \"POS\" : \"nm\", \"sense\" : \" \"}, \"Note\" : \"\"}, "+
" \"1\" :{ "+
" \"OriginalTerm\" : { \"term\" : \"cat\", \"POS\" : \"n\", \"sense\" : \"member of cat family\", \"usage\" : \"\"}, "+
" \"FirstTranslation\" : {\"term\" : \"felino\", \"POS\" : \"nm\", \"sense\" : \"familia de animales\"}, \"Note\" : \"\"}},"+
" \"AdditionalTranslations\" : { "+
" \"0\" :{ "+
" \"OriginalTerm\" : { \"term\" : \"cat\", \"POS\" : \"n\", \"sense\" : \"guy\", \"usage\" : \"slang\"}, "+
" \"FirstTranslation\" : {\"term\" : \"tío, tipo, chaval\", \"POS\" : \"nm\", \"sense\" : \"coloq\"}, "+
" \"SecondTranslation\" : {\"term\" : \"vato\", \"POS\" : \"\", \"sense\" : \"Mex\"}, \"Note\" : \"\"}, "+
" "+
" \"original\" : { "+
" \"Compounds\" : { "+
" \"0\" :{ "+
" \"OriginalTerm\" : { \"term\" : \"alley cat\", \"POS\" : \"n\", \"sense\" : \"stray cat\", \"usage\" : \"\"}, "+
" \"FirstTranslation\" : {\"term\" : \"gato callejero\", \"POS\" : \"nm\", \"sense\" : \"\"}, \"Note\" : \"\"}, "+
" \"Lines\" : \"End Reached\", \"END\" : true "+
" "+
" } "+
" } }}} ";
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(json);
JsonElement je2 = je.getAsJsonObject().get("term0");
JsonElement je3 = je2.getAsJsonObject().get("PrincipalTranslations");
Type mapType = new TypeToken<Map<String, Item>>() {}.getType();
Map<String, Item> principalTranslation = new Gson().fromJson(je3, mapType);
System.out.println(principalTranslation);
}
}
And this is my execution:
{0=Item [OriginalTerm=Term [term=cat, POS=n, sense=domestic animal, usage=], FirstTranslation=Term [term=gato, POS=nm, sense= , usage=null], Note=],
1=Item [OriginalTerm=Term [term=cat, POS=n, sense=member of cat family, usage=], FirstTranslation=Term [term=felino, POS=nm, sense=familia de animales, usage=null], Note=]}
I think this could help: http://www.newthinktank.com/2013/07/android-development-15/
It's a video tutorial explaining the how to use json. Not through GSON though, but I think you need a base on how JSON works before getting involved in GSON (it's rather complicated)

Categories