Scala: Edit/Modify json string based on internal value - json

I have a json string structured similarly to the following:
val json : String =
{
"identifier":{
"id":"1234_567_910",
"timestamp":"12:34:56",
},
"information":[
{
"fieldName":"test_name",
"fieldId":"test_fieldId",
}
]
}
What I want to do is create a check that verifies the 'id' field matches the structure "Int_Int_Int" and if it doesn't I want to change the value to match this intended structure but I want to keep the rest of the information in the json string as is.
So if I received the following 'id' fields within a json string I would want to change them like so:
"id":"1234_567_910" -> do nothing
"id":"1234" -> "id":"1234_0_0"
"id":"1234_567" -> "id":"1234_567_0"
"id":"1234_???" -> "id":"1234_0_0"
"id":"1234_??_???" -> "id":"1234_0_0"
"id":"1234_foo" -> "id":"1234_0_0"
"id":"1234_567_foo" -> "id":"1234_567_0"
For Example:
If I receive json like this:
{
"identifier":{
"id":"1234",
"timestamp":"12:34:56",
},
"information":[
{
"fieldName":"test_name",
"fieldId":"test_fieldId",
}
]
}
I would want to modify it so I end up with a json like this:
{
"identifier":{
"id":"1234_0_0",
"timestamp":"12:34:56",
},
"information":[
{
"fieldName":"test_name",
"fieldId":"test_fieldId",
}
]
}
What would be the most effective/cleanest way to achieve this type of json modification in Scala?

Below is how it can be done with the Dijon library.
import com.github.pathikrit.dijon._
def normalize(id: String): String =
id.count(_ == '_') match {
case 0 => id + "_0_0"
case 1 => id + "_0"
case _ => id
}
val json =
json"""
{
"identifier":{
"id":"1234",
"timestamp":"12:34:56"
},
"information":[
{
"fieldName":"test_name",
"fieldId":"test_fieldId"
}
]
}"""
json.identifier.id = json.identifier.id.asString.fold("0_0_0")(normalize)
println(pretty(json))
It should print:
{
"identifier": {
"id": "1234_0_0",
"timestamp": "12:34:56"
},
"information": [
{
"fieldName": "test_name",
"fieldId": "test_fieldId"
}
]
}

Related

How to flatten json array using typescript and Convert it as object

I am trying to convert a json array as a flat json using typescript.
I have a json as below:
"Fields" : [
{
"FieldName" : "xyz";
"FieldValue" : {
"Contents": {
" Company": "ABC"
}
}
}
]
I have to convert as below:
"xyz" : {
"Contents": {
" Company": "ABC"
}
}
Here Fields should be replaced with "xyz", FieldName and FieldValue should need to be removed.
Help me to achieve this using typescript.
If you really only want to work with that first item in your array just rearrange the data with something the following.
const json = JSON.stringify({
Fields: [
{
FieldName: "xyz",
FieldValue: {
Contents: {
" Company": "ABC"
}
}
}
]
});
const parsedJson = JSON.parse(json);
const expectedOutput = {
[parsedJson.Fields[0].FieldName]: parsedJson.Fields[0].FieldValue
};
console.log(expectedOutput);

Convert List to Json

How do I create a Json (Circe) looking like this:
{
"items": [{
"field1": "somevalue",
"field2": "somevalue2"
},
{
"field1": "abc",
"field2": "123abc"
}]
}
val result = Json.fromFields(List("items" -> ???))
You can do so using Circe's built in list typeclasses for encoding JSON. This code will work:
import io.circe.{Encoder, Json}
import io.circe.syntax._
case class Field(field1: String, field2: String)
object Field {
implicit val encodeFoo: Encoder[Field] = new Encoder[Field] {
final def apply(a: Field): Json = Json.obj(
("field1", Json.fromString(a.field1)),
("field2", Json.fromString(a.field2))
)
}
}
class Encoding(items: List[Field]) {
def getJson: Json = {
Json.obj(
(
"items",
items.asJson
)
)
}
}
If we instantiate an "Encoding" class and call getJson it will give you back the desired JSON. It works because with circe all you need to do to encode a list is provide an encoder for whatever is inside the list. Thus, if we provide an encoder for Field it will encode it inside a list when we call asJson on it.
If we run this:
val items = new Encoding(List(Field("jf", "fj"), Field("jfl", "fjl")))
println(items.getJson)
we get:
{
"items" : [
{
"field1" : "jf",
"field2" : "fj"
},
{
"field1" : "jfl",
"field2" : "fjl"
}
]
}

How to get Keys and values, while parsing Json using Scala-Play Json Framework?

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

Scala play JSON, lookup and match defined field holding null value

I have the following Json block that I have returned as a JsObject
{
"first_block": [
{
"name": "demo",
"description": "first demo description"
}
],
"second_block": [
{
"name": "second_demo",
"description": "second demo description",
"nested_second": [
{
"name": "bob",
"value": null
},
{
"name": "john",
"value": null
}
]
}
]
}
From this, I want to return a list of all the possible values I could have in the second block, nested array for name and value. so with the example above
List([bob,null],[john,null]) or something along those lines.
The issue I am having is with the value section understanding null values. I've tried to match against it and return a string "null" but I can't get it to match on Null values.
What would be the best way for me to return back the name and values in the nested_second array.
I've tried using case classes and readAsNullable with no luck, and my latest attempt has gone along these lines:
val secondBlock = (jsObj \ "second_block").as[List[JsValue]]
secondBlock.foreach(nested_block => {
val nestedBlock = (nested_block \ "nested_second").as[List[JsValue]]
nestedBlock.foreach(value => {
val name = (value \ "name").as[String] //always a string
var convertedValue = ""
val replacement_value = value \ "value"
replacement_value match {
case JsDefined(null) => convertedValue = "null"
case _ => convertedValue = replacement_value.as[String]
}
println(name)
println(convertedValue)
})
}
)
It seems convertedValue returns as 'JsDefined(null)' regardless and I'm sure the way I'm doing it is horrifically bad.
Replace JsDefined(null) with JsDefined(JsNull).
You probably got confused, because println(JsDefined(JsNull)) prints as JsDefined(null). But that is not, how null value of a JSON field is represented. null is represented as case object JsNull. This is just a good API design, where possible cases are represented with a hierarchy of classes:
With play-json I use always case-classes!
I simplified your problem to the essence:
import play.api.libs.json._
val jsonStr = """[
{
"name": "bob",
"value": null
},
{
"name": "john",
"value": "aValue"
},
{
"name": "john",
"value": null
}
]"""
Define a case class
case class Element(name: String, value: Option[String])
Add a formatter in the companion object:
object Element {
implicit val jsonFormat: Format[Element] = Json.format[Element]
}
An use validate:
Json.parse(jsonStr).validate[Seq[Element]] match {
case JsSuccess(elems, _) => println(elems)
case other => println(s"Handle exception $other")
}
This returns: List(Element(bob,None), Element(john,Some(aValue)), Element(john,None))
Now you can do whatever you want with the values.

How to update a key value in JSON dynamically?

I have a JSON like below
{
"context":{
"parameters":[
{
"name":"stub",``
"value": {"item value":"abcdefg"}
},
{
"name":"category",
"value":{"item value":"cars"}
},
{
"name":"year",
"value":{"item value":"2012"}
},
{
"name":"make",
"value":{"item value":"toyota"}
},
{
"name":"cars",
"value":{"item value":"corolla"}
}
]
}
I am supplied with a two strings dynamically like "cars" and "accord". I need to search for "cars" and then replace the "item value" under it to "accord". I have tried to convert it to map but have no success.
Any suggestions about how I can achieve this?
Here's one way to do it in Groovy.
Assuming that the JSON is like so (I have corrected it; there are illegal chars in the original question):
def s = '''
{
"context":{
"parameters":[
{
"name":"stub",
"value": {"item value":"abcdefg"}
},
{
"name":"category",
"value":{"item value":"cars"}
},
{
"name":"year",
"value":{"item value":"2012"}
},
{
"name":"make",
"value":{"item value":"toyota"}
},
{
"name":"cars",
"value":{"item value":"corolla"}
}
]
}
}
'''
then consider:
import groovy.json.*
def jsonSlurper = new JsonSlurper().parseText(s)
def category = jsonSlurper.context.parameters.find { it.name == "cars" }
category.value."item value" = "accord"
println new JsonBuilder(jsonSlurper).toPrettyString()
you can do that with javascript. If you are working with JSON format you can parse that data to an object.
const data = JSON.parse("your json data")
data.context.parameters.map(param => {
if ( param.name !== "cars") {
return param
}
return {
"name": "cars",
value: {"accord": "corolla"}
}
})