lift what is the difference \ and \\ operators when parsing json - lift

using net.liftweb.json what is the difference \ and \ operators when parsing json ?
import net.liftweb.json._
val parsed = JsonParser.parse(jsonString)
val name = parsed.\("firstName")
val userId = parsed.\\("userId")

"\\" will extract the value even if it's present within nested json whereas "\" will extract the value only if present as a top-level attribute.
Consider this json
val json = """{"nested1":{"nested2": {"myKey":"myValue"}}}"""
val jsonMsg = parse(json)
In this case
(jsonMsg \ "myKey").values
retruns None
where as
(jsonMsg \\ "myKey").values
returns myValue

Related

json4s parse return null

I am trying to get value from a nested JSON using json4s in scala.
The parse method works well for the string provided manually but null for the string provided from a file.
Here is the code
import org.json4s.jackson.JsonMethods.{parse, pretty}
import scala.io.Source
object ParseJson4s {
def map_fields(lines: String) = {
val testString = """{"Information":{"Context":"firstContext", "Assets":{"Asset":{"Name":"firstName"}}}}"""
val parseJSON_test = parse(testString)
val parseJSON = parse(lines)
println("Name from method " + pretty(parseJSON_test \ "Information" \ "Assets" \ "Asset" \ "Name"))
println("Name from file " + pretty(parseJSON \ "Information" \ "Assets" \ "Asset" \ "Name"))
}
def main(args: Array[String]): Unit = {
val file = Source.fromFile("testFile.txt").getLines()
file.foreach(map_fields)
}
}
and here is the test file
"""{"Information":{"Context":"firstContext", "Assets":{"Asset":{"Name":"firstName"}}}}"""
"""{"Information":{"Context":"secondContext", "Assets":{"Asset":{"Name":"secondName"}}}}"""
Output:
Name from method "firstName"
Name from file
Name from method "firstName"
Name from file
Thanks
Is """ mandadory for JSON records in your text file? I removed them and it works for me.
Results I've got in console:
Name from file "firstName"
Name from file "secondName"
Source code:
import org.json4s.jackson.JsonMethods.{parse, pretty}
import scala.io.Source
object Json4sTest {
def map_fields(lines: String) = {
val parseJSON = parse(lines)
println("Name from file " + pretty(parseJSON \ "Information" \ "Assets" \ "Asset" \ "Name"))
}
def main(args: Array[String]): Unit = {
val file = Source.fromFile("testFile.txt").getLines()
file.foreach(map_fields)
}
}
testFile.txt:
{"Information":{"Context":"firstContext", "Assets":{"Asset":{"Name":"firstName"}}}}
{"Information":{"Context":"secondContext", "Assets":{"Asset":{"Name":"secondName"}}}}
The reason why it fails is because the lines in the file are not valid JSON strings. A JSON string cannot start with triple quotes or quotes for that matter, unless it's just a simple string.
Triple quote(""") in scala is used to create multi-line strings and strings that contain quotes within them. You need to use them only when you define string literals(hard code strings) in scala.
So, remove the triple quotes from the lines in the file and it should give you proper results.
Try to parse from the file with jsoniter-scala, it will clearly report a position and a cause of the problem.
https://github.com/plokhotnyuk/jsoniter-scala

How to read json array in scala using the Play framework

I have the following Json as var dataObject ={"files": ["code.R", "data.cv", "input.txt"]}.
I am posting this json as a body from the client side and I want to parse the Json and read these files names in the server side in play scala.
Please help
Because you have only one field, you can't use json combinators,
But you can do as follow:
case class Selection(files:List[String])
object Selection{
implicit val selectionReads = (__ \ 'files).read[List[String]].map{ l => Selection(l) }
implicit val selectionWrites = (__ \ 'files).write[List[String]].contramap { (selection: Selection) => selection.files}
//You can replace the above 2 lines with this line - depends on you.
implicit val selectionFormat: Format[Selection] = (__ \ 'files).format[List[String]].inmap(files => Selection(files), (selection: Selection) => selection.files)
}
Make sure you import:
import play.api.libs.functional.syntax._
This is the documentation: https://www.playframework.com/documentation/2.5.x/ScalaJson
And the solution is simple:
import play.api.libs.json._
val json: JsValue = Json.parse("{ "files": ["code.R","data.csv","input.txt"] }")
val files = (json \ "files").get

Converting JDouble to Double (JSON library)

I'm using https://github.com/json4s/json4s. How do I convert its values such as JDouble, JBool to corresponding Scala's data types -- Double and Boolean?
UPDATE:
scala> (json \ "status")
res8: org.json4s.JValue = JBool(false)
scala> (json \ "status").extract[Boolean]
<console>:16: error: No org.json4s.Formats found. Try to bring an instance of org.json4s.Formats in scope or use the org.json4s.DefaultFormats.
(json \ "status").extract[Boolean]
As mentioned in Read Me, heres how you do it.. :)
import org.json4s._
import org.json4s.native.JsonMethods._
implicit val formats = DefaultFormats
val json = parse("""
{
"mydouble" : 3.14,
"isPie" : true
}
""")
val dbl = (json \ "mydouble").extractOpt[Double]
//> dbl : Option[Double] = Some(3.14)
val bool = (json \ "isPie").extractOpt[Boolean]
//> bool : Option[Boolean] = Some(true)
Looking at the code (https://github.com/json4s/json4s/blob/7c70e9664232ffee4acf24c8969424cd37957736/ast/src/main/scala/org/json4s/JsonAST.scala) shows that you just need to call the JValue.values method.
UPDATE: From your comment it seems that it's not so much that you have a JDouble and want to extract its Double value (and similarly extract a Boolean from a JDouble. Instead, you have a JValue
and want to extract its value as a Double or Boolean (knowing in advance the expected type).
This can be done with extract, as explained in the README that you linked to:
(json \ "status").extract[Double]
or:
(json \ "status").extract[Boolean]
See also this test file for more examples:
https://github.com/json4s/json4s/blob/master/tests/src/test/scala/org/json4s/ExtractionExamplesSpec.scala

Lift JSON LINQ Like Dynamic Extraction Pattern

I am attempting to perform an XPath based extraction using Lift JSON except that the xpath pattern of extraction is determined during runtime
To illustrate, I'd like to convert string "a.b.c.d" to Lift JSON extraction using (json \ "a" \ "b" \ "c").extract[List[Int]]
import net.liftweb.json._
import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonAST._
import net.liftweb.json.Extraction._
implicit val formats = net.liftweb.json.DefaultFormats
val x = """{ "a" : { "b" : [ {"c" : 10},{ "c" : 20 } ] } }"""
val json = parse(x)
val dataString = "a.b.c"
val dataList = dataString.split("\\.").toList
// List(a,b,c)
// I'd want to convert the above string to - (json \ "a" \ "b" \ "c").extract[List[Int]]
Is it possible to use foldLeft to achieve this pattern?
If I understand your question, this is what you want:
List("a", "b", "c").foldLeft(json){ _ \ _ }.extract[List[Int]]
And to help understand why:
foldLeft takes two arguments; an initial state, and a function that takes the "current" state and the next input, returning the "next" state. The "inputs" are the elements of the thing you're calling foldLeft on, i.e. the List("a", "b", "c").
So if you use json as your initial state, the first state change call will be json \ "a". The next will be the result of that calculation, backslash "b", and so on.

PlayFramework 2.0 Json to List[String] Conversion

Converting json to oher type should be easy. From the Play! documentation:
var str = "{\"next_cursor\":0,\"ids\":[123123,345345],\"previous_cursor\":0}"
var fol = Json.parse(str)
var fin = Json.fromJson[List[String]].fromJson(fol)
Should work without problem. It compiles fine, but failed with this error:
[RuntimeException: List expected]
Instead, this works:
var str = "{\"next_cursor\":0,\"ids\":[123123,345345],\"previous_cursor\":0}"
var fol = Json.parse(str)
var fin = (fol \ "ids") match {
case ids: JsArray => ids.value.map(_.toString)
case _ => JsArray()
}
Why? Am I understanding something wrong with the API? I'm trying this in PlayFramework 2.0.1.
You can't parse this as a List[String] directly, as it is a list of numbers, not strings. Your match example works because you map the ids to a string afterwards. Using your example, you'd write it more like:
val str = "{\"next_cursor\":0,\"ids\":[123123,345345],\"previous_cursor\":0}"
val fol = Json.parse(str)
val fin = Json.fromJson[List[Int]](fol \ "ids")
To make the syntax slightly easier to read, I'd make use of JsValue.as[T], which is the equivalent of Json.fromJson[T]:
val fin = (fol \ "ids").as[List[Int]]
And if you need the ids to be converted to strings:
val fin = (fol \ "ids").as[List[Int]].map(_.toString)