Como posso construir e analisar uma string JSON em Scala / Elevador
Pergunta
Eu estou tentando usar JSON para enviar dados entre o navegador eo meu aplicativo.
Eu estou tentando usar Levante 1.0 para criar e cordas JSON de análise, mas por alguma razão eu sou incapaz de analisar o JSON Eu só construídos:
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
Como faço para programaticamente construir uma mensagem JSON válido em Scala / Levante, que também pode ser analisado novamente?
Solução
Você está usando JsCmd
Levante 1.0 de, que produz JSON com cordas individuais citado e tentar analisá-lo com analisador de scala, que só suporta strings delimitadas por aspas.
É importante perceber que existem várias definições para JSON.
são strings de aspas válida em JSON?
- Eles estão de acordo com a ECMAScript 5ª Ed
- Eles não estão de acordo com o Crockford originais RFC 4627
Levante e Scala fornecer muitas maneiras de analisar JSON, às vezes com diferentes comportamento entre as versões.
As cordas aceites por estes analisadores não são equivalentes.
Aqui estão alguns comentários e exemplos dos vários métodos para produto e cordas JSON de análise.
Producing JSON com a lift-json DSL biblioteca
- Recomendado
- Apesar do nome, este é um projeto separado com nenhuma dependência sobre o resto do Levante
exemplo:
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]}
Análise de JSON com a lift-json biblioteca
- Recomendado
- Fornece mapeamento implícito de / para o Scala de caso-classes
- Casos de classes definidas no console não são suportadas atualmente (irá lançar um
com.thoughtworks.paranamer.ParameterNamesNotFoundException: Unable to get class bytes
) - O exemplo abaixo usa
PublicID
, um pré-existente scala caso de classe para que ele irá trabalhar na consola scala.
exemplo:
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"
Análise de JSON em Scala 2.7.7 e 2.8.1
- Não Recomendado - " Já não realmente suportado "
- analisador Scala 2.7.7 de não analisar single-citado JSON
- Este método de análise utilizado na questão
exemplo:
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
Análise de JSON Elevação 2.0 e 2.2 com util.JSONParser
- recomendação Neutral
- util.JSONParser do Elevador irá analisar cordas JSON simples ou dupla citou:
exemplo:
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))
Análise de JSON Elevação 2.0 e 2.2 com json.JsonParser
- recomendação Neutral
- json.JsonParser do elevador não irá analisar cordas JSON único citado:
exemplo:
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...
Producing JSON com elevação de 1,0 JsCmd
- Não Recomendado - saída não é válido para todos os analisadores JSON
- Observe o single-citações ao redor strings:
exemplo:
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]
}
Producing JSON com Elevador 2,0 JsCmd
- recomendação Neutral
- Observe as aspas duplas em torno de strings:
exemplo:
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]
}
Producing JSON em scala (testado com 2,10)
- " Já não realmente suportado ", mas funciona e é lá.
exemplo:
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]}
Outras dicas
Dê uma olhada Circe . É muito bom de usar e que aproveita algumas das novas ferramentas de Shapeless e Cats . Além disso, você pode usá-lo a partir Scala compilado para Javascript .
Retirado do Circe readme :
scala> importação io.circe. , io.circe.generic.auto. , io.circe.parser. , io.circe.syntax. importação io.circe._ io.circe.generic.auto._ importação importação importação io.circe.parser._ io.circe.syntax ._
scala> característica selada Foo definido traço Foo
scala> classe caso Bar (xs: Lista [String]) se estende Foo definido classe Bar
scala> classe caso qux (i: Int, d: Opção [dupla]) estende Foo definida classe Qux
scala> Val foo: Foo = qux (13, Alguns (14,0)) foo: Foo = Qux (13, Alguns (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, Alguns (14,0)))