How to extract the numbers from json path using scala - json

My response will be like:
{
"code" : 201,
"message" : "Your Quote Id is 353541551"
}
From this above response I have to extract the number 353541551 alone, so I tried with the basic scala snippets. I tried the following:
.check((status is 201),(jsonPath("Your Quote Id is(//d{9})").saveAs("quoteid")))
And another snippet:
.check((status is 201),(jsonPath("$.message.([0-9]+)").saveAs("quoteid")))
But both didn't work
Please help me out to extract the numbers

Try to use spary json; https://github.com/spray/spray-json
You can define json data structure using scala case class and define custom apply/unapply methods if required.
case class JsonResponse(code: Int, message: String)
object JsonResponse { implicit val f = JsonFormat2(JsonResponse.apply)}
you can use scala Regex to pattern match the string to extract the required value.

Related

Kotlin: JSON string with linebreaker and variable

I would like to add linebreakers to a JSON string so it will be more readable.
val myString = "some string"
val myObjectJson = `
{
"example1": "value",
"example2": $myString
}`
So later I can use ObjectMapper to create an object. objectMapper.readValue(myObjectJson, MyClass::class.Java)
What I'm trying to figure out:
How to add lineBreaker in Json string?
Tried template literals:"`", doesn't seem to work in Kotline. gives Expecting an expression error.
How to use variable in Json string?
This might go away after I figure out how to add linebreakers.
(Edited because I think I have misunderstood your question).
Are you asking how to lay out a JSON string in the source code? If so then what you are looking for is the Raw String feature implemented with 3 double-quotes like this:
val myObjectJson = """
{
"example1": "value",
"example2": $myString
}
"""
But in case you asking
How to add lineBreaker in Json string?
(Assuming you are using Jackson's ObjectMapper)
Simply use writerWithDefaultPrettyPrinter() like this: MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(value)
If that is not good enough for you I suppose you could implement a custom Pretty Printer: https://www.javadoc.io/static/com.fasterxml.jackson.core/jackson-core/2.14.2/com/fasterxml/jackson/core/PrettyPrinter.html

PlayJSON in Scala

I am trying to familiarize myself with the PlayJSON library. I have a JSON formatted file like this:
{
"Person": [
{
"name": "Jonathon",
"age": 24,
"job": "Accountant"
}
]
}
However, I'm having difficulty with parsing it properly due to the file having different types (name is a String but age is an Int). I could technically make it so the age is a String and call .toInt on it later but for my purposes, it is by default an integer.
I know how to parse some of it:
import play.api.libs.json.{JsValue, Json}
val parsed: JsValue = Json.parse(jsonFile) //assuming jsonFile is that entire JSON String as shown above
val person: List[Map[String, String]] = (parsed \ "Person").as[List[Map[String, String]]]
Creating that person value throws an error. I know Scala is a strongly-typed language but I'm sure there is something I am missing here. I feel like this is an obvious fix too but I'm not quite sure.
The error produced is:
JsResultException(errors:List(((0)/age,List(JsonValidationError(List(error.expected.jsstring),WrappedArray())))
The error you are having, as explained in the error you are getting, is in casting to the map of string to string. The data you provided does not align with it, because the age is a string. If you want to keep in with this approach, you need to parse it into a type that will handle both strings and ints. For example:
(parsed \ "Person").validate[List[Map[String, Any]]]
Having said that, as #Luis wrote in a comment, you can just use case class to parse it. Lets declare 2 case classes:
case class JsonParsingExample(Person: Seq[Person])
case class Person(name: String, age: Int, job: String)
Now we will create a formatter for each of them on their corresponding companion object:
object Person {
implicit val format: OFormat[Person] = Json.format[Person]
}
object JsonParsingExample {
implicit val format: OFormat[JsonParsingExample] = Json.format[JsonParsingExample]
}
Now we can just do:
Json.parse(jsonFile).validate[JsonParsingExample]
Code run at Scastie.

How to convert response body in Json using play framework

override def accessToken(): ServiceCall[RequestTokenLogIn, Done] = {
request=>
val a=request.oauth_token.get
val b=request.oauth_verifier.get
val url=s"https://api.twitter.com/oauth/access_token?oauth_token=$a&oauth_verifier=$b"
ws.url(url).withMethod("POST").get().map{
res=>
println(res.body)
}
The output which I am getting on terminal is
oauth_token=xxxxxxxxx&oauth_token_secret=xxxxxxx&user_id=xxxxxxxxx&screen_name=xxxxx
I want to convert this response in json format.like
{
oauth_token:"",
token_secret:"",
}
When Calling res.json.toString its not converting into jsValue.
Is there any other way or am I missing something?
According to the documentation twitter publishes, it seems that the response is not a valid json. Therefore you cannot convert it automagically.
As I see it you have 2 options, which you are not going to like. In both options you have to do string manipulations.
The first option, which I like less, is actually building the json:
print(s"""{ \n\t"${res.body.replace("=", "\": \"").replace("&", "\"\n\t\"")}" \n}""")
The second option, is to extract the variables into a case class, and let play-json build the json string for you:
case class TwitterAuthToken(oauth_token: String, oauth_token_secret: String, user_id: Long, screen_name: String)
object TwitterAuthToken {
implicit val format: OFormat[TwitterAuthToken] = Json.format[TwitterAuthToken]
}
val splitResponse = res.body.split('&').map(_.split('=')).map(pair => (pair(0), pair(1))).toMap
val twitterAuthToken = TwitterAuthToken(
oauth_token = splitResponse("oauth_token"),
oauth_token_secret = splitResponse("oauth_token_secret"),
user_id = splitResponse("user_id").toLong,
screen_name = splitResponse("screen_name")
)
print(Json.toJsObject(twitterAuthToken))
I'll note that Json.toJsObject(twitterAuthToken) returns JsObject, which you can serialize, and deserialize.
I am not familiar with any option to modify the delimiters of the json being parsed by play-json. Given an existing json you can manipulate the paths from the json into the case class. But that is not what you are seeking for.
I am not sure if it is requires, but in the second option you can define user_id as long, which is harder in the first option.

Extract list of fields from Nested Json using Json4s Scala

I am trying to parse the nested Json and get the list of name from the fields tag.
{
"subject": "table-name",
"version": 1,
"id": 234,
"schema": "{
\"type\":\"record\",\"name\":\"table-name\",
\"fields\":[
{\"name\":\"NAME\",\"type\":\"CHARACTER\},
{\"name\":\"EID\",\"type\":\"INT\"},
{\"name\":\"DEPARTMENT\",\"type\":\"CHARACTER\"}
]
}"
}
I checked couple of post and came up with below code. I can get the schema definition(which is fairly easy) but not able to the list of name from fields.
case class Names(name : String)
case class FieldNames(fields: List[Names])
case class ColNames(subject: String, schema: FieldNames)
implicit val formats = DefaultFormats
val sourceSchema = parse("JsonStr").extract[ColNames]
println(sourceSchema)
My idea was the part schema: FieldNames will get me the fields tag and then List[Names] will get me the list of name but all I get is empty list. If I change the schema: FieldNames with schema: String I get the schema too but I am not getting how to get the required list of name after that. Below is the current output:
ColNames(table-name,FieldNames(List()))
Update:
I got it working but I ended up parsing the same Json twice which I don't feel is a best way of doing it. I would still like to know the best way to get it done. Below is my current solution:
case class Name(name : String)
case class FieldNames(fields: List[Name])
case class ColNames(subject: String, schema: String)
val sourceSchema = parse("JsonStr").extract[ColNames]
val cols= parse(sourceSchema.schema).extract[FieldNames]
Output:
FieldNames(List(Name(NAME), Name(EID), Name(DEPARTMENT)))

how to format scala's output from JSON to text file format

I am using Scala with Spark with below version.
Scala - 2.10.4
Spark - 1.2.0
I am mentioning below my situation.
I have a RDD(Say - JoinOp) with nested tuples(having case classes), for example -
(123,(null,employeeDetails(Smith,NY,DW)))
(456,(null,employeeDetails(John,IN,CS)))
This RDD is being created from a Join with two files.
Now, my requirement is to convert this JSON format to text file format without any "Null" and any case class name(here 'employeeDetails').
My desired output is =
123,Smith,NY,DW
456,John,IN,CS
I have tried with String Interpolation for the same but with partial success.
val textOp = JoinOp.map{jm => s"${jm._1},${jm._2._2}"}
if I print textOp then it will give me below output.
123,employeeDetails(Smith,NY,DW)
456,employeeDetails(John,IN,CS)
Now if I try to access nested elements in "employeeDetails" case class with String interpolation, it will throwing error like below.
JoinOp.map{jm => s"${jm._1},${jm._2._2._1}"}.foreach(println)
<console> :23: Error : value _1 is not member of jm
Here I can understand that, with the above syntax, it's unable to access nested element for "employeeDetails" case class.
What might be the solution for this issue. Any help or point forward would be of much help.
Many Thanks,
Pralay
Case classes have field names. So, instead of ._1 you need to use the field name for that position. Assuming the following definition:
case class EmployeeDetails(name: String, state: String)
you would access it
JoinOp.map{jm => s"${jm._1},${jm._2._2.name}"}.foreach(println)
If you just need to print all fields of case class, you may use productIterator to traverse field list.
val textOp = JoinOp.map { jm =>
s"""${jm._1},${jm._2._2.productIterator.mkString(",")}"""
}
You can do it like this:
case class EmployeeDetails(var0: String, var1: String, var2: String)
val data = List((123,(null, EmployeeDetails("Smith", "NY", "DW"))))
data.map {case (num, (sth, EmployeeDetails(var0, var1, var2))) =>
s"$num,$var0,$var1,$var2"}