How do I transform the json below using scala lift based on a sibling attribute?
In the json below, I want to encode the value in "value" attribute if sibling attribute "type" is "html"
val json = """
{
"id" : "1B23423B",
"payload" : {
"list" : [ {
"name" : "test",
"data" : [ {
"value" : "Some html",
"type" : "html",
}, {
"value" : "some text",
"type" : "text"
}]
}]
}
}
"""
def encode(s:String):String = s + "encoded"
val newjson = js.transform {
case x if x == JField("type",JString("html")) => // somehow encode value??
}
println(newjson)
Here is on of the possible solutions:
1) first find data json with type html
2) transform json value child
val parsed = JsonParser.parse(jsonString)
def encode(s:String):String = s + "encoded"
private def encodeValue(dataObject: JValue) = dataObject.transform{
case JField("value", JString(value)) => JField("value", JString(encode(value)))
}
val newJson = parsed.transform({
case dataObject # JObject(fields) if fields.contains(JField("type", JString("html"))) => encodeValue(dataObject)
})
Related
I have the below json file which I want to split in NIFI
Input:
[ {
"id" : 123,
"ticket_id" : 345,
"events" : [ {
"id" : 3322,
"type" : "xyz"
}, {
"id" : 6675,
"type" : "abc",
"value" : "sample value",
"field_name" : "subject"
}, {
"id" : 9988,
"type" : "abc",
"value" : [ "text_file", "json_file" ],
"field_name" : "tags"
}]
}]
and my output should be 3 different jsons like below:
{
"id" : 123,
"ticket_id" : 345,
"events.id" :3322,
"events.type":xyz
}
{
"id" : 123,
"ticket_id" : 345,
"events.id" :6675,
"events.type":"abc",
"events.value": "sample value"
"events.field_name":"subject"
}
{
"id" : 123,
"ticket_id" : 345,
"events.id" :9988,
"events.type":"abc",
"events.value": "[ "text_file", "json_file" ]"
"events.field_name":"tags"
}
I want to know can we do it using splitjson? I mean can splitjson split the json based on the array of json objects present inside the json?
Please let me know if there is a way to achieve this.
If you want 3 different flow files, each containing one JSON object from the array, you should be able to do it with SplitJson using a JSONPath of $ and/or $.*
Using reduce function:
function split(json) {
return json.reduce((acc, item) => {
const events = item.events.map((evt) => {
const obj = {id: item.id, ticket_id: item.ticket_id};
for (const k in evt) {
obj[`events.${k}`] = evt[k];
}
return obj;
});
return [...acc, ...events];
}, []);
}
const input = [{"id":123,"ticket_id":345,"events":[{"id":3322,"type":"xyz"},{"id":6675,"type":"abc","value":"sample value","field_name":"subject"},{"id":9988,"type":"abc","value":["text_file","json_file"],"field_name":"tags"}]}];
const res = split(input);
console.log(res);
I have a json file , which has some keys and values. I need to parse the Json and print the keys and their values. For example, the json file is like below. I want to print this as Keys and values
{
"Parcer":[
{
"key":"0203",
"value":{
"Encryption":
{
"enabled":"yes",
"encryption_type":"base64",
"key":"334848484",
"return":"name"
}
}
},
{
"key":"0405",
"value":{
"Encryption":
{
"enabled":"yes",
"encryption_type":"base64",
"key":"334848484",
"return":"none"
},
"Parcer":[
{
"key":"0102",
"value":"humidity"
},
{
"key":"0304",
"value":{
"Encryption":{
"enabled":"yes",
"encryption_type":"SHA1",
"key":"1211212",
"return":"none"
}
}
}
]
}
}],
}```
The easiest way is to create a case class, like:
case class MyObj(header:String, value: Seq[Map[String, String]])
Then you just need to add one line for marshalling, like:
import play.api.libs.json._
object MyObj {
implicit val jsonFormat: OFormat[MyObj] = Json.format[MyObj]
}
Now you get a nice case class that you can work with:
val json =
Json.parse(
"""{
"header" : "header value",
"value" : [
{
"a" : "a_val",
"b" : "b_val",
"c" : "c_val"
},
{
"a" : "a_val",
"b" : "b_val",
"c" : "c_val"
}
]
}""")
Here an example how to retrieve all "a".
json.validate[MyObj] match {
case JsSuccess(myObj, _) =>
val allAs =myObj.value.flatMap(m => m.get("a").toSeq)
println(allAs) // >> Vector(a_val, a_val)
case e:JsError => // handle error
}
This gives you:
json.validate[MyObj] returns JsSuccess(MyObj(header value,Vector(Map(a -> a_val, b -> b_val, c -> c_val), Map(a -> a_val, b -> b_val, c -> c_val))),)
The println returns: Vector(a_val, a_val)
This is described here in the Documentation: JSON automated mapping
I have a json file of the format
{"latitude":28.488069,"longitude":-81.407208,"data":[{"time":1462680000,"summary":"Clear"},{"time":1462683600,"summary":"Clear",},{"time":1462694400,"summary":"Clear"}]}}
I want to add id attribute inside data
val result = jsonfile
val Jsonobject = Json.parse(result).as[JsObject]
val res = Jsonobject ++ Json.obj("id" -> 1234)
println(Json.prettyPrint(res))
the output should be
{"latitude":28.488069,"longitude":-81.407208,"data":[{"time":1462680000,"summary":"Clear","id":"1234"},{"time":1462683600,"summary":"Clear","id":"1235"},{"time":1462694400,"summary":"Clear","id":"1236"}]}
but my output is
{"latitude":28.488069,"longitude":-81.407208,"data":[{"time":1462680000,"summary":"Clear"},{"time":1462683600,"summary":"Clear",},{"time":1462694400,"summary":"Clear"}]},"id":"1234"}
There are a couple of things missing in your code. In your expected output, the ID is incremented, how do you expect to just add "id" -> 1234 and have it automatically incremented ?
Anyway, you have to loop through the elements in data and set it for each one of them. Something like this works:
val j = Json.parse(result).as[JsObject]
val res = j ++ Json.obj("data" ->
// get the 'data' array and loop inside
(j \ "data").as[JsArray].value.zipWithIndex.map {
// zipWithIndex lets us use the index to increment the ID
case (x,i) => x.as[JsObject] + ("id" , JsString((1234 + i).toString)) })
println(Json.prettyPrint(res))
{
"latitude" : 28.488069,
"longitude" : -81.407208,
"data" : [ {
"time" : 1462680000,
"summary" : "Clear",
"id" : "1234"
}, {
"time" : 1462683600,
"summary" : "Clear",
"id" : "1235"
}, {
"time" : 1462694400,
"summary" : "Clear",
"id" : "1236"
} ]
}
I'm comparing 2 jsons with JSR223 Assertion and I'm willing to remove the ids from all levels from the response json:
{
"id" : 52906,
"name1" : "559812 Company name1",
"name2" : "559812 Company name2",
"country" : "DE",
"interests" : {
"id" : 848675,
"description" : false
},
"emails" : [ {
"id" : 904881,
"address" : "559812#gmail.com"
} ],
...
I'm using the following Groovy code:
def slurper2 = new JsonSlurper();
def jsonResponse = slurper2.parseText(prev.getResponseDataAsString());
jsonResponse.rows.findAll { it.remove("id") };
But it doesn't work - Please advise.
I don't really understand where you got this rows bit as I don't see any JSON Array named "rows" in your response.
If you want to remove all "id" attributes you can use the following approach:
def response = prev.getResponseDataAsString()
def responseWithoutIds = response.replaceAll("\"id\"[ ]*:[^,}\\]]*[,]?", "")
// do what you need with the modified response, i.e. store it into a JMeter Variable
vars.put("responseWithoutIds", responseWithoutIds)
Demo:
References:
String.replaceAll() method JavaDoc
Pattern class JavaDoc
Apache Groovy - Why and How You Should Use It
import groovy.json.*;
def s='''{
"id" : 52906,
"name1" : "559812 Company name1",
"name2" : "559812 Company name2",
"country" : "DE",
"interests" : {
"id" : 848675,
"description" : false
},
"emails" : [ {
"id" : 904881,
"address" : "559812#gmail.com"
} ]
}
'''
def removeAttr(node, attr){
if(node instanceof Map){
node.remove(attr)
node.each{ k,v-> removeAttr(v, attr) }
}else if(node instanceof List){
node.each{ i-> removeAttr(i, attr) }
}
}
def slurper2 = new JsonSlurper();
def jsonResponse = slurper2.parseText(s);
removeAttr(jsonResponse,"id")
println JsonOutput.prettyPrint(JsonOutput.toJson(jsonResponse))
I've a List of a type which contains three fields (services, total, improved). When I convert it to JSON using Json.toJson(myList), I get the JSON in the following format:
[
{
"services":"S4",
"total":1,
"improved":1
},
{
"services":"S1",
"total":2,
"improved":1
},
{
"services":"S2",
"total":3,
"improved":2
}
]
Using JSON library in Play 2.x in Scala, how can I convert myList in the following JSON format?
[
{
"key" : "total",
"values" :[
{
"services" : "s1",
"value" : 2
},
"services" : "s2",
"value" : 3
{
"services" : "s4",
"value" : 1
}
]
},
{
"key" : "improved",
"values" :[
{
"services" : "s1",
"value" : 1
},
"services" : "s2",
"value" : 2
{
"services" : "s4",
"value" : 1
}
]
}
]
Thanks in advance.
Since you are already dealing with OO, I think you could wrap your List into a more specific object and convert it to JSON :
case class Foo(services: String, total: Int, improved: Int)
case class B(key: String, value: Int)
case class A(key: String, values: Seq[B] = Seq())
val myOriginalList = Seq(Foo("S4", 1, 1), Foo("S1", 2, 1), Foo("S2", 3, 2))
val transformedList = myOriginalList.foldLeft((A("total"), A("improved")))({ (res, x) =>
(res._1.copy(values = B(x.services, x.total) +: res._1.values),
res._2.copy(values = B(x.services, x.improved) +: res._2.values))
}).map({x => List(x._1, x._2)})
Json.toJson(transformedList)
One of the problem (or maybe not) using this solution, is that you don't resolve the Foo attributes dynamically.
You could also try yourself around Json Transformers : http://www.playframework.com/documentation/2.2.x/ScalaJsonTransformers
Here's a Scala newbie's solution (I'm sure it's not elegant):
I'm using a solution provided here: http://www.playframework.com/documentation/2.1.1/ScalaJson
//some data
case class PatientAggregateValues(total: Int, improved: Int)
val scoreMap = Map.empty[String, PatientAggregateValues]
scoreMap += ("S1" -> PatientAggregateValues(2, 1))
scoreMap += ("S2" -> PatientAggregateValues(3, 2))
scoreMap += ("S4" -> PatientAggregateValues(1, 1))
//main logic
val totalMap = scoreMap map { case (k,v) => Json.toJson(scala.collection.immutable.Map("service" -> Json.toJson(k), "value" -> Json.toJson(v.total))) } toSeq
val improvedMap = scoreMap map { case (k,v) => Json.toJson(scala.collection.immutable.Map("service" -> Json.toJson(k), "value" -> Json.toJson(v.improved))) } toSeq
Json.toJson(scala.collection.immutable.Map("total" -> totalMap, "improved" -> improvedMap))
Thanks.