web-dev-qa-db-fra.com

Comment puis-je construire et analyser une chaîne JSON dans Scala/Lift

J'essaie d'utiliser JSON pour envoyer des données entre le navigateur et mon application.

J'essaie d'utiliser Lift 1.0 pour créer et analyser des chaînes JSON, mais pour une raison quelconque, je suis incapable d'analyser le JSON que je viens de construire:

scala>import scala.util.parsing.json.JSON._
import scala.util.parsing.json.JSON._

scala> import net.liftweb.http.js._
import net.liftweb.http.js._

scala> import net.liftweb.http.js.JE._
import net.liftweb.http.js.JE._

scala> val json = JsObj(("foo", 4), ("bar", "baz")).toJsCmd
json: String = {'foo': 4, 'bar': 'baz'}

scala>  parseFull(json)  
res3: Option[Any] = None

Comment créer par programme un message JSON valide dans Scala/Lift qui puisse également être analysé à nouveau?

54
David Carlson

Vous utilisez la variable JsCmd de Lift 1.0, qui produit JSON avec des chaînes entre guillemets simples et vous essayez de l'analyser avec l'analyseur de scala, qui ne prend en charge que les chaînes entre guillemets doubles.

Il est important de réaliser qu'il existe plusieurs définitions pour JSON.

Les chaînes entre guillemets simples sont-elles valides en JSON?

Lift et Scala offrent de nombreuses façons d’analyser JSON, parfois avec des comportements différents selon les versions.

Les chaînes acceptées par ces analyseurs ne sont pas équivalentes.

Voici quelques commentaires et exemples des différentes méthodes de production et d’analyse de chaînes JSON.


Produire JSON avec la bibliothèque DSL lift-json

  • Conseillé
  • Malgré son nom, il s’agit d’un projet séparé, dépendant du reste de Lift.

exemple:

scala> import net.liftweb.json.JsonAST
import net.liftweb.json.JsonAST

scala> import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonDSL._

scala> import net.liftweb.json.Printer._
import net.liftweb.json.Printer._

scala> val json1 = ("foo" -> 4) ~ ("bar" -> "baz")
json1: net.liftweb.json.JsonAST.JObject = JObject(List(JField(foo,JInt(4)), JField(bar,JString(baz))))

scala> compact(JsonAST.render(json1))
res0: String = {"foo":4,"bar":"baz"}

scala> val json2 = List(1,2,3)
json2: List[Int] = List(1, 2, 3)

scala> compact(JsonAST.render(json2))
res1: String = [1,2,3]

scala> val json3 = ("foo", 4) ~ ("bar", List(1,2,3))
json3: net.liftweb.json.JsonAST.JObject = JObject(List(JField(foo,JInt(4)), JField(bar,JArray(List(JInt(1), JInt(2), JInt(3))))))

scala> compact(JsonAST.render(json3))
res2: String = {"foo":4,"bar":[1,2,3]}

Analyse de JSON avec la bibliothèque lift-json

  • Conseillé
  • Fournit un mappage implicite vers/depuis les classes de cas scala
  • Les classes de cas définies dans la console ne sont actuellement pas prises en charge (lancera un com.thoughtworks.paranamer.ParameterNamesNotFoundException: Unable to get class bytes)
  • L'exemple ci-dessous utilise PublicID, une classe de cas scala préexistante pour qu'il puisse fonctionner sur la console scala.

exemple:

scala> import scala.xml.dtd.PublicID
import scala.xml.dtd.PublicID

scala> import net.liftweb.json._
import net.liftweb.json._

scala> import net.liftweb.json.JsonAST._
import net.liftweb.json.JsonAST._

scala> import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonDSL._

scala> implicit val formats = DefaultFormats 
formats: net.liftweb.json.DefaultFormats.type = net.liftweb.json.DefaultFormats$@7fa27edd

scala> val jsonAst = ("publicId1" -> "idString") ~ ("systemId" -> "systemIdStr")
jsonAst: net.liftweb.json.JsonAST.JObject = JObject(List(JField(publicId,JString(idString)), JField(systemId,JString(systemIdStr))))

scala> jsonAst.extract[PublicID]
res0: scala.xml.dtd.PublicID = PUBLIC "idString" "systemIdStr"

Analyse de JSON dans les graphiques 2.7.7 et 2.8.1

  • Non recommandé - " N'est plus vraiment supporté "
  • L'analyseur de Scala 2.7.7 n'analysera pas le code JSON à une seule citation 
  • Cette méthode d'analyse utilisée dans la question

exemple:

scala>import scala.util.parsing.json.JSON._
import scala.util.parsing.json.JSON._

scala>  parseFull("{\"foo\" : 4 }")        
res1: Option[Any] = Some(Map(foo -> 4.0))

scala> parseFull("[ 1,2,3 ]")
res2: Option[Any] = Some(List(1.0, 2.0, 3.0))

scala>  parseFull("{'foo' : 4 }")  
res3: Option[Any] = None

Analyse de JSON dans Lift 2.0 et 2.2 avec util.JSONParser

  • Recommandation neutre
  • Le fichier util.JSONParser de Lift analysera les chaînes JSON entre guillemets simples ou doubles:

exemple:

scala> import net.liftweb.util.JSONParser._
import net.liftweb.util.JSONParser._

scala> parse("{\"foo\" : 4 }")    
res1: net.liftweb.common.Box[Any] = Full(Map(foo -> 4.0))

scala> parse("[ 1,2,3 ]")
res2: net.liftweb.common.Box[Any] = Full(List(1.0, 2.0, 3.0))

scala> parse("{'foo' : 4}")           
res3: net.liftweb.common.Box[Any] = Full(Map(foo -> 4.0))

Analyse de JSON dans Lift 2.0 et 2.2 avec json.JsonParser

  • Recommandation neutre
  • Json.JsonParser de Lift n'analysera pas les chaînes JSON entre guillemets simples:

exemple:

scala> import net.liftweb.json._
import net.liftweb.json._

scala> import net.liftweb.json.JsonParser._
import net.liftweb.json.JsonParser._

scala> parse("{\"foo\" : 4 }")
res1: net.liftweb.json.JsonAST.JValue = JObject(List(JField(foo,JInt(4))))

scala> parse("[ 1,2,3 ]")
res2: net.liftweb.json.JsonAST.JValue = JArray(List(JInt(1), JInt(2), JInt(3)))

scala> parse("{'foo' : 4}")    
net.liftweb.json.JsonParser$ParseException: unknown token '
Near: {'foo' : 4}
    at net.liftweb.json.JsonParser$Parser.fail(JsonParser.scala:216)
    at net.liftweb.json.JsonParser$Parser.nextToken(JsonParser.scala:308)
    at net.liftweb.json.JsonParser$$anonfun$1.apply(JsonParser.scala:172)
    at net.liftweb.json.JsonParser$$anonfun$1.apply(JsonParser.scala:129)
    at net.liftweb.json.JsonParse...

Produire JSON avec Lift 1.0 JsCmd

  • Non recommandé - la sortie n'est pas valide pour tous les analyseurs JSON
  • Notez les guillemets simples autour des chaînes:

exemple:

scala> import net.liftweb.http.js._
import net.liftweb.http.js._

scala> import net.liftweb.http.js.JE._
import net.liftweb.http.js.JE._

scala> JsObj(("foo", 4), ("bar", "baz")).toJsCmd
res0: String = {'foo': 4, 'bar': 'baz'}

scala> JsArray(1,2,3).toJsCmd
res1: String = 
[1, 2, 3]

scala>  JsObj(("foo", 4), ("bar", JsArray(1,2,3))).toJsCmd
res2: String = 
{'foo': 4, 'bar': [1, 2, 3]
}

Production de JSON avec Lift 2.0 JsCmd

  • Recommandation neutre
  • Notez les doubles citations autour des chaînes:

exemple:

scala> import net.liftweb.http.js._
import net.liftweb.http.js._

scala> import net.liftweb.http.js.JE._
import net.liftweb.http.js.JE._

scala> JsObj(("foo", 4), ("bar", "baz")).toJsCmd
res0: String = {"foo": 4, "bar": "baz"}

scala> JsArray(1,2,3).toJsCmd
res1: String = 
[1, 2, 3]

scala> JsObj(("foo", 4), ("bar", JsArray(1,2,3))).toJsCmd
res3: String = 
{"foo": 4, "bar": [1, 2, 3]
}

Producint JSON en scala (testé avec 2.10)

exemple:

scala> import scala.util.parsing.json._
import scala.util.parsing.json._

scala> JSONObject (Map ("foo" -> 4, "bar" -> JSONArray (1 :: 2 :: 3 :: Nil))) .toString()
res0: String = {"foo" : 4, "bar" : [1, 2, 3]}
87
David Carlson

Jetez un oeil à Circé . Il est vraiment agréable à utiliser et exploite certains des nouveaux outils de Shapeless et Cats . De plus, vous pouvez l’utiliser à partir de Scala compilé en Javascript .

Tiré du readme Circé :

scala> import io.circe ., io.circe.generic.auto., io.circe.parser ., io.circe.syntax. import io.circe._ import io.circe.generic.auto ._ importer io.circe.parser._ importer io.circe.syntax._

scala> trait scellé Foo trait défini Foo

scala> barre de classe de cas (xs: List [String]) étend la barre de classe définie par Foo

scala> classe de cas Qux (i: Int, d: Option [Double]) étend la définition de Foo classe Qux

scala> val foo: Foo = Qux (13, Some (14.0)) foo: Foo = Qux (13, Certains (14.0))

scala> foo.asJson.noSpaces res0: String = {"Qux": {"d": 14.0, "i": 13}}

scala> decodeFoo res1: cats.data.Xor [io.circe.Error, Foo] = Droite (Qux (13, Some (14.0)))

0
James Moore