55 votes

Comment construire et analyser une chaîne JSON en 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 ne parviens pas à 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 construire par programme un message JSON valide en Scala/Lift qui peut également être analysé à nouveau ?

89voto

David Carlson Points 899

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

Il est important de savoir qu'il existe plusieurs définitions de JSON.

Les chaînes de caractères entre guillemets simples sont-elles valables dans JSON ?

Lift et Scala proposent de nombreuses façons d'analyser JSON, parfois avec des comportements différents d'une version à l'autre.

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

Voici quelques commentaires et exemples des différentes méthodes pour produire et analyser les chaînes JSON.


Produire du JSON avec la fonction lift-json bibliothèque DSL

  • Recommandé
  • Malgré son nom, il s'agit d'un projet séparé qui ne dépend pas 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 fonction lift-json bibliothèque

  • Recommandé
  • Fournit une correspondance implicite vers/depuis les classes de cas scala
  • Les classes de cas définies dans la console ne sont actuellement pas prises en charge (elles provoqueront un com.thoughtworks.paranamer.ParameterNamesNotFoundException: Unable to get class bytes )
  • L'exemple ci-dessous utilise [PublicID](http://www.scala-lang.org/api/current/scala/xml/dtd/PublicID.html) , une classe de cas scala préexistante pour qu'elle fonctionne 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 scala 2.7.7 et 2.8.1

  • Non recommandé - " Il n'y a plus vraiment de soutien "
  • L'analyseur de Scala 2.7.7 n'analyse pas le JSON entre guillemets simples.
  • La 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
  • L'util.JSONParser de Lift analyse 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'analyse pas les chaînes JSON entre guillemets :

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 du 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 de caractères :

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]
}

Produire du JSON avec Lift 2.0 JsCmd

  • Recommandation neutre
  • Notez les doubles guillemets autour des chaînes de caractères :

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]
}

Produire du 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]}

3 votes

Il s'agit d'une excellente réponse, mais elle semble un peu dépassée aujourd'hui. Cependant, je ne sais pas si c'est une pratique acceptée par StackOverflow d'apporter des modifications majeures à une entrée. Les principaux problèmes sont qu'il devrait y avoir une référence à la bibliothèque Twitter JSON (basée sur scala-json) et à la bibliothèque Jerkson (utilisant Jackson). De plus, la référence au support intégré de Scala ne mentionne pas Scala 2.9.x.

3 votes

L'objectif initial de SO était d'éviter le problème des forums en ligne, à savoir que les messages vivent éternellement, mais finissent par être périmés, et que personne ne les déprécie ou ne les marque comme n'étant plus pertinents. Compte tenu de cela, et du fait qu'il s'agit d'une réponse wiki communautaire, je vous suggère de changer !

3 votes

Vous avez tort d'affirmer que la 5e édition de l'ECMA spécifie que les chaînes JSON peuvent avoir des guillemets simples. À la page 202, la spécification indique clairement des guillemets doubles. Par conséquent, votre affirmation concernant la multiplicité des normes est également invalidée. Il existe une norme JSON unique, définie par Crockford, qui a ensuite été incluse dans la spécification de l'ECMA 5ème édition. Les implémentations qui génèrent ou valident des chaînes JSON avec des guillemets simples ne sont pas valides.

0voto

James Moore Points 3293

Jetez un coup d'œil à Circé . Il est vraiment agréable à utiliser et tire parti de certains des nouveaux outils de Sans forme y Chats . De plus, vous pouvez l'utiliser à partir de Scala compilé en Javascript .

Tiré de la Circe readme :

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

scala> sealed trait Foo defined trait Foo

scala> case class Bar(xs : List[String]) extends Foo defined class Bar

scala> case class Qux(i : Int, d : Option[Double]) extends Foo defined classe Qux

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

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X