My JSON string is:
{name:"MyNode", width:200, height:100}
I want to change it to:
{name:"MyNode", width:"200", height:"100"}
so that all integer values become strings
My main code is:
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"xy": 10021
},
"IDNumber":
[
{
"type": "home",
"number": 1234
},
{
"type": "fax",
"number": 4567
}
]
}
I need all integer values become strings
That's a JavaScript object literal, not JSON. Anyway...
var obj = {name:"MyNode", width:200, height:100};
for (var k in obj)
{
if (obj.hasOwnProperty(k))
{
obj[k] = String(obj[k]);
}
}
// obj = {name:"MyNode", width: "200", height: "100"}
If you're actually working with JSON, not an object, JSON.parse() the string beforehand, and JSON.stringify() the object afterward.
If you must operate on the JSON string :
json = json.replace (/:(\d+)([,\}])/g, ':"$1"$2');
I use
const stringifyNumbers = obj => {
const result = {};
Object.entries(obj).map(entry => {
const type = typeof entry[1];
if (Array.isArray(entry[1])) {
result[entry[0]] = entry[1].map(entry => stringifyNumbers(entry));
} else if (type === 'object' && !!entry[1]) {
result[entry[0]] = stringifyNumbers(entry[1]);
} else if (entry[1] === null) {
result[entry[0]] = null;
} else if (type === 'number') {
result[entry[0]] = String(entry[1]);
} else {
result[entry[0]] = entry[1];
}
});
return result;
}
most ids should be strings in my opinion. If your api cannot provide ids as strings this snippet will convert them.
Related
I want to add a new field to jsonObject and this new field's name will be based on a value of another field. To be clear, this an examples of what I want to achieve.
{
"values": [
{
"id": "1",
"properties": [
{
"stat": "memory",
"data": 8
},
{
"stat": "cpu",
"data": 4
}
]
},
{
"id": "2",
"properties": [
{
"stat": "status",
"data": "OK"
},
{
"stat": "cpu",
"data": 4
}
]
}
]
}
I want to add a new field to each json object that will have the value of field "stat" as name.
{
"values": [
{
"id": "1",
"properties": [
{
"stat": "memory",
"data": 8,
"memory": 8
},
{
"stat": "cpu",
"data": 4,
"cpu": 4
}
]
},
{
"id": "2",
"properties": [
{
"stat": "status",
"data": 0,
"status": 0
},
{
"stat": "cpu",
"data": 4,
"cpu": 4
}
]
}
]
}
I have tried to do the following with JsonPath library but for me it's an ugly solution as I will parse the json three times and I do some manual replacements.
val configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.ALWAYS_RETURN_LIST).build()
val jsonContext5 = JsonPath.using(configuration).parse(jsonStr)
val listData = jsonContext.read("$['values'][*]['properties'][*]['data']").toString
.replace("[", "").replace("]", "").split(",").toList
val listStat = jsonContext.read("$['values'][*]['properties'][*]['stat']").toString
.replace("[", "").replace("]", "")
.replace("\"", "").split(",").toList
// Replacing values of "stat" by values of "data"
jsonContext5.map("$['values'][*]['properties'][*]['stat']", new MapFunction() {
var count = - 1
override def map(currentValue: Any, configuration: Configuration): AnyRef = {
count += 1
listData(count)
}
})
// replace field stat by its value
for( count <- 0 to listStat.size - 1){
val path = s"['values'][*]['properties'][$count]"
jsonContext5.renameKey(path, "stat", s"${listStat(count)}")
}
This is the result obtained
{
"values": [
{
"id": "1",
"properties": [
{
"data": 8,
"memory": "8"
},
{
"data": 4,
"cpu": "4"
}
]
},
{
"id": "2",
"properties": [
{
"data": 0,
"memory": "0"
},
{
"data": 4,
"cpu": "4"
}
]
}
]
}
Is there any better method to achieve this result ? I tried to do it with gson but it's not good handling paths.
This a way to do it with Gson but I will lose the information about other columns since I'm creating another json.
val jsonArray = jsonObject.get("properties").getAsJsonArray
val iter = jsonArray.iterator()
val agreedJson = new JsonArray()
while(iter.hasNext) {
val json = iter.next().getAsJsonObject
agreedJson.add(replaceCols(json))
}
def replaceCols(json: JsonObject) = {
val fieldName = "stat"
if(json.has(fieldName)) {
val columnName = json.get(fieldName).getAsString
val value: String = if (json.has("data")) json.get("data").getAsString else ""
json.addProperty(columnName, value)
}
json
}
How about something like this?
private static void statDup(final JSONObject o) {
if (o.containsKey("properties")) {
final JSONArray a = (JSONArray) o.get("properties");
for (final Object e : a) {
final JSONObject p = (JSONObject) e;
p.put(p.get("stat"), p.get("data"));
}
} else {
for (final Object key : o.keySet()) {
final Object value = o.get(key);
if (value instanceof JSONArray) {
for (final Object e : (JSONArray) value) {
statDup((JSONObject) e);
}
}
}
}
}
Using Gson, what you should do is create a base class that represents your initial JSON object. Then, extend that class and add the additional attribute(s) you want to add, such as "stat". Then, load the JSON objects into memory, either one by one or all together, then make the necessary changes to each to encompass your changes. Then, map those changes to the new class if you didn't in the prior step, and serialize them to a file or some other storage.
This is type-safe, a pure FP circe implementation with circe-optics:
object CirceOptics extends App {
import cats.Applicative
import cats.implicits._
import io.circe.{Error => _, _}
import io.circe.syntax._
import io.circe.parser._
import io.circe.optics.JsonPath._
val jsonStr: String = ???
def getStat(json: Json): Either[Error, String] =
root.stat.string.getOption(json)
.toRight(new Error(s"Missing stat of string type in $json"))
def getData(json: Json): Either[Error, Json] =
root.data.json.getOption(json)
.toRight(new Error(s"Missing data of json type in $json"))
def setField(json: Json, key: String, value: Json) =
root.at(key).setOption(Some(value))(json)
.toRight(new Error(s"Unable to set $key -> $value to $json"))
def modifyAllPropertiesOfAllValuesWith[F[_]: Applicative](f: Json => F[Json])(json: Json): F[Json] =
root.values.each.properties.each.json.modifyF(f)(json)
val res = for {
json <- parse(jsonStr)
modifiedJson <- modifyAllPropertiesOfAllValuesWith { j =>
for {
stat <- getStat(j)
data <- getData(j)
prop <- setField(j, stat, data)
} yield prop
} (json)
} yield modifiedJson
println(res)
}
The previous answer from Gene McCulley gives a solution with Java and using class net.minidev.json. This answer is using class Gson and written in Scala.
def statDup(o: JsonObject): JsonObject = {
if (o.has("properties")) {
val a = o.get("properties").getAsJsonArray
a.foreach { e =>
val p = e.getAsJsonObject
p.add(p.get("stat").getAsString, p.get("data"))
}
} else {
o.keySet.foreach { key =>
o.get(key) match {
case jsonArr: JsonArray =>
jsonArr.foreach { e =>
statDup(e.getAsJsonObject)
}
}
}
}
o
}
Your task is to add a new field to each record under each properties in the JSON file, make the current stat value the field name and data values the new field values. The code will be rather long if you try to do it in Java.
Suggest you using SPL, an open-source Java package to get it done. Coding will be very easy and you only need one line:
A
1
=json(json(file("data.json").read()).values.run(properties=properties.(([["stat","data"]|stat]|[~.array()|data]).record())))
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as addfield.splx and invoke it in a Java application as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call addfield()");
st.execute();
…
I have an soapui response like below and i tried to parse the same and print all the elements(From leaf node) in the json response.
Sample Json :
{
"BookID": 7982,
"author": {
"authorname": "roboin"
},
"authorid": "X-1-23",
"BookDetails": [{
"Price": "100",
"Location": "Paris"
}],
"authordob": "1980-11-10",
"Adverts": {
"online": true
}
}
Use of below groovy script is to print all the elements in the response.The below code goes to each and every element in the Json response and print like below Expected Result,
Expected Result: Print all the element(leaf node) jsonpath and values
$.['author']['authorname'] : roboin
$.['BookDetails'][0]['Price']:100
Current Result : Prints all the elements and values
authorname : roboin
Price:100
import groovy.json.*
//Get the test case response from context and parse it
def contextResponse = messageExchange.getResponseContent().toString()
//log.info(contextResponse)
def parseResponse = new JsonSlurper().parseText(contextResponse)
//log.info(parseResponse)
def parseMap(map) {
map.each {
if (it.value instanceof Map) {
parseMap(it.value)
} else if (it.value instanceof List) {
log.info(it.key + ": ")
parseArray(it.value)
} else {
log.info(it.key + ": " + it.value)
}
}
}
def parseArray(array) {
array.each {
if (it instanceof Map) {
parseMap(it)
} else if (it instanceof List) {
parseArray(it)
} else {
log.info("arrayValue: $it");
}
}
}
parseMap(parseResponse)
I tried some research about this and found few json path selector in online and that can't be used inside my soapui application.i want to iterate and print all the elements json path and their values.
Currently the above code iterate and prints only the element name and values.
def j=new groovy.json.JsonSlurper().parseText('''{
"BookID": 7982,
"author": {
"authorname": "roboin"
},
"authorid": "X-1-23",
"BookDetails": [{
"Price": "100",
"Location": "Paris"
}],
"authordob": "1980-11-10",
"Adverts": {
"online": true
}
}''')
void printJsonPaths(o, path='$'){
if(o instanceof Map){
o.each{ k,v-> printJsonPaths(v, path+"['${k}']") }
}else if(o instanceof List){
o.eachWithIndex{ v,i-> printJsonPaths(v, path+"[${i}]") }
}else{
println("${path}: ${o}")
}
}
printJsonPaths(j)
output
$['BookID']: 7982
$['author']['authorname']: roboin
$['authorid']: X-1-23
$['BookDetails'][0]['Price']: 100
$['BookDetails'][0]['Location']: Paris
$['authordob']: 1980-11-10
$['Adverts']['online']: true
I have received a json string like so:
{
"data": [
{
"name": "Order",
"value": "2"
},
{
"name": "Address",
"value": "182"
},
{
"name": "DNS",
"value": "null"
},
{
"name": "SSID",
"value": "work"
},
{
"name": "Protocol",
"value": "0"
},
{
"name": "Key",
"value": ""
},
{
"name": "carrier",
"value": "undefined"
},
{
"name": "SSH",
"value": "1"
},
{
"name": "ntp_addr",
"value": ""
},
{
"name": "Name",
"value": ""
}
]
}
I used stringify on an html response and this is what I have to parse. As you can see, it is pretty redundant; I would much rather { "Order":"2" } than { "name":"Order","value":"2" } ... So an array of name-value pairs, instead of an array of objects.
Is there a way I can dynamically format this response so that it will be easier to parse?
What 'd like is to be able to say:
JSONObject jsonObject = new JSONObject(jsonResponse);
JSONArray data = jsonObject.getJSONArray("data");
for (int i = 0; i < data.length(); i++) {
JSONObject dataObject = data.getJSONObject(i);
String order = dataObject.getString("Order");
String address = dataObject.getString("Address");
// etc...
}
But the current format makes it almost impossible to parse. I'd need loops within loops.
I'd like to use com.google.gson library. And this response easy to parse with it:
private final JsonParser PARSER = new JsonParser();
public void parse(String jsonString) {
JsonObject dataObject = PARSER.parse(jsonString).getAsJsonObject();
JsonArray dataArray = dataObject.get("data").getAsJsonArray();
dataArray.iterator().forEachRemaining(element -> {
String name = element.getAsJsonObject().get("name").getAsString();
String value = element.getAsJsonObject().get("value").getAsString();
}
}
Or you can simply use TypeAdapters for json deserialization directly in the object.
Something like this should do the trick
JSONObject jsonObject = new JSONObject(jsonResponse);
JSONArray data = jsonObject.getJSONArray("data");
JSONObject simplifiedDataObject = new JSONObject();
for (int i = 0; i < data.length(); i++) {
JSONObject dataField = data.getJSONObject(i);
simplifiedDataObject.put(dataField.getString("name"), dataField.get("value"));
}
You just iterate over each element in data, use the name field as the field on a new JSONObject and simply retrieve the value using the value key.
May I know how to get JSON object from a json array??
JSON:
[
{
"id": 1,
"region": "Ilocos Region (Region I)",
"province": "Ilocos Norte",
"city": "Laoag City"
},
{
"id": 2,
"region": "Ilocos Region (Region I)",
"province": "Ilocos Norte",
"city": "Batac City"
},
{
"id": 3,
"region": "Ilocos Region (Region I)",
"province": "Ilocos Sur",
"city": "Vigan City"
}
]
I can get the region, province and city but I can't get the id.
Here is the code I'm using:
try {
br = new BufferedReader(new FileReader(path+"json/src_city.json"));
try {
while ((inputline = br.readLine()) != null) {
JSONArray a = (JSONArray) parser.parse(inputline);
for (Object o : a) {
JSONObject sample = (JSONObject) o;
id = (int) sample.get("id");
}}
if you can get the region, may be the reason is the id is int,you can not get by the way like this: id = (int) sample.get("id");
I think Jason uses only string values, try surrounding the number in quotes:
{
"id": "1",
"region": "Ilocos Region (Region I)",
"province": "Ilocos Norte",
"city": "Laoag City"
},
then you can parse it back to integer after retrieving it out of the object
id = Integer.valueOf(sample.get("id"));
We can get each jsonnode from the json array as shown below. And jsonnode provides method to parse the integer also.
if (a.isArray()) {
for (final JsonNode objNode : a) {
id = objNode.get("id").asInt();
}
}
[
{
"ID": 5,
"Name": "pratik"
},
{
"ID": 6,
"Name": "pratiksha"
},
{
"ID": 7,
"Name": "pratikshaman"
}
]
I want to display only : 6 Pratiksha
Not too clear on what your trying to achieve... is this what your wanting?
//The json string
var jsonString = '[{"ID":5,"Name":"pratik"},{"ID":6,"Name":"pratiksha"},{"ID":7,"Name":"pratikshaman"}]',
//The json array
jsonArray = JSON.parse(jsonString),
//search function to returns entry by id
jsonSearch = function(id){
return jsonArray.filter(function(obj){
return obj.ID === id;
});
};
console.log(jsonSearch(6)); //Array contains your Pratiksha object and any other matches
http://jsfiddle.net/uckpL5bt/