Comment puis-je construire et analyser une chaîne JSON à Scala / Lift
Question
Je tente d'utiliser JSON pour envoyer des données entre le navigateur et mon application.
Je cherche à utiliser Lift 1.0 pour créer et analyser des chaînes JSON, mais pour une raison que je ne peux pas analyser le JSON Je viens construisais:
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 puis-je construis un message JSON programme valable dans Scala / Lift qui peut également être analysé à nouveau?
La solution
Vous utilisez le JsCmd
de Lift 1.0, qui produit JSON avec des chaînes entre guillemets simples et en essayant de l'analyser avec l'analyseur de scala, qui ne supporte que les chaînes entre guillemets doubles.
Il est important de se rendre compte qu'il existe plusieurs définitions pour JSON.
sont des chaînes entre guillemets simples valable dans JSON?
- Ils sont selon ECMAScript 5ème Ed
- Ils ne sont pas selon RFC 4627
Lift et Scala offrent de nombreuses façons de parser JSON, parfois avec des comportements différents entre les versions.
Les chaînes acceptées par ces parseurs ne sont pas équivalents.
Voici quelques commentaires et des exemples des différentes méthodes de produits et analyser des chaînes JSON.
La production JSON avec le plate-forme élévatrice JSON DSL bibliothèque
- recommandé
- Malgré son nom, c'est un projet distinct sans dépendances sur le reste de levage
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]}
JSON avec le Parsing rel="nofollow plate-forme élévatrice JSON bibliothèque
- recommandé
- Fournit la cartographie implicite / des classes de cas-scala
- Case-classes définies dans la console ne sont pas actuellement pris en charge (jetteront un
com.thoughtworks.paranamer.ParameterNamesNotFoundException: Unable to get class bytes
) - L'exemple ci-dessous utilise
PublicID
, un cas de classe scala préexistante afin qu'il 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"
JSON dans scala Parsing 2.7.7 et 2.8.1
- Non recommandé - « plus vraiment soutenu "
- l'analyseur de Scala 2.7.7 n'analysera pas JSON guillemets simples
- 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
Parsing JSON Ascenseur 2,0 et 2,2 avec util.JSONParser
- Recommandation neutre
- util.JSONParser de Lift analysera les chaînes JSON simple ou double cité:
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))
Parsing JSON Ascenseur 2,0 et 2,2 avec json.JsonParser
- Recommandation neutre
- json.JsonParser de levage ne sera pas analyser des 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...
Production JSON avec Lift 1.0 JsCmd
- Non recommandé - sortie non valable pour tous les parseurs JSON
- Notez les mono-cotations autour de 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 JSON avec Lift 2.0 JsCmd
- Recommandation neutre
- Notez les doubles guillemets 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]
}
La production JSON dans scala (testé avec 2.10)
- " plus vraiment soutenu », mais il fonctionne et il est là.
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]}
Autres conseils
Jetez un oeil à Circé . Il est vraiment agréable à utiliser et il tire parti de quelques-uns des nouveaux outils de et Shapeless Chats . De plus, vous pouvez l'utiliser à partir Scala compilé Javascript .
Tiré du Circé readme :
scala> io.circe d'importation. , io.circe.generic.auto. , io.circe.parser. , io.circe.syntax. import io.circe._ io.circe.generic.auto._ import importation io.circe.syntax importation io.circe.parser._ ._
scala> trait scellé Foo trait défini Foo
scala> Bar cas de classe (xs: Liste [String]) étend barre de classe Foo défini
scala> classe affaire qux (i: Int, d: Option [Double]) étend Foo défini 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] = Droite (qux (13, Some (14,0)))