【问题标题】:How can I construct and parse a JSON string in Scala / Lift如何在 Scala / Lift 中构造和解析 JSON 字符串
【发布时间】:2010-10-30 00:05:21
【问题描述】:

我正在尝试使用 JSON 在浏览器和我的应用程序之间发送数据。

我正在尝试使用 Lift 1.0 创建和解析 JSON 字符串,但由于某种原因我无法解析我刚刚构建的 JSON:

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

如何以编程方式在 Scala/Lift 中构造一个也可以再次解析的有效 JSON 消息?

【问题讨论】:

    标签: json scala lift


    【解决方案1】:

    您正在使用 Lift 1.0 的 JsCmd,它会生成带有单引号字符串的 JSON,并尝试使用仅支持双引号字符串的 scala 解析器对其进行解析。

    重要的是要意识到 JSON 有多种定义。

    单引号字符串在 JSON 中有效吗?

    Lift 和 Scala 提供了许多解析 JSON 的方法,有时版本之间的行为不同。

    这些解析器接受的字符串是不等价的。

    这里有一些 cmets 以及生成和解析 JSON 字符串的各种方法的示例。


    使用lift-json 库 DSL 生成 JSON

    • 推荐
    • 尽管名称如此,但这是一个独立的项目,不依赖于 Lift 的其余部分

    示例:

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

    使用 lift-json 库解析 JSON

    • 推荐
    • 提供与 Scala 案例类之间的隐式映射
    • 当前不支持在控制台中定义的案例类(将抛出 com.thoughtworks.paranamer.ParameterNamesNotFoundException: Unable to get class bytes
    • 下面的示例使用 @987654325@,这是一个预先存在的 scala 案例类,因此它可以在 scala 控制台上运行。

    示例:

    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"
    

    在 scala 2.7.7 和 2.8.1 中解析 JSON

    • 不推荐 - “No longer really supported
    • Scala 2.7.7 的解析器不会解析单引号 JSON
    • 问题中使用的这种解析方法

    示例:

    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
    

    在 Lift 2.0 和 2.2 中使用 util.JSONParser 解析 JSON

    • 中性推荐
    • Lift 的 util.JSONParser 将解析单引号或双引号的 JSON 字符串:

    示例:

    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))
    

    在 Lift 2.0 和 2.2 中使用 json.JsonParser 解析 JSON

    • 中性推荐
    • Lift 的 json.JsonParser 不会解析单引号 JSON 字符串:

    示例:

    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...
    

    使用 Lift 1.0 JsCmd 生成 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> 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]
    }
    

    使用 Lift 2.0 JsCmd 生成 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> 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]
    }
    

    在 scala 中生成 JSON(用 2.10 测试)

    示例:

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

    【讨论】:

    • 这是一个很好的回应,但现在感觉有点过时了。但是,我不知道对条目进行重大编辑是​​否被接受 StackOverflow 做法。对我来说主要的问题是应该引用 Twitter JSON 库(基于 scala-json)和 Jerkson(使用 Jackson)库。此外,对内置 Scala 支持的引用没有提及 Scala 2.9.x。
    • 嗯,SO 最初的目标是避免在线论坛的问题 - 帖子永远存在,但最终会变得陈旧,并且没有人会弃用它们或将它们标记为不再相关。鉴于此,再加上这是一个社区 wiki 答案,我建议您改掉!
    • 您在说明 ECMA 第 5 版时是不正确的。指定 JSON 字符串可以有单引号。在第 202 页,规范清楚地说明了双引号。因此也使您对多个标准的陈述无效。 Crockford 定义了一个 JSON 标准,随后被包含在 ECMA 第 5 版中。规格。使用单引号生成或验证 JSON 字符串的实现无效。
    • 我正在尝试使用 lift-json 库将地图转换为 json。这是我的代码: var x = compact(JsonAST.render(y)) ,这里 y 是一张地图。我收到以下错误:类型不匹配; [错误] 发现:scala.collection.immutable.Map[String,List[String]] [错误] 需要:net.liftweb.json.JsonAST.JValue。我该怎么办?我什至找不到将地图更改为所需格式的方法。
    【解决方案2】:

    看看Circe。它使用起来真的很好,它利用了来自ShapelessCats 的一些新工具。另外,您可以通过Scala compiled to Javascript 使用它。

    取自Circe readme

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

    scala> 密封特征 Foo 定义特征 Foo

    scala> case class Bar(xs: List[String]) extends Foo 定义的类 Bar

    scala> case class Qux(i: Int, d: Option[Double]) extends Foo 定义 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: cat.data.Xor[io.circe.Error,Foo] = Right(Qux(13,Some(14.0)))

    【讨论】:

      猜你喜欢
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 2017-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-24
      相关资源
      最近更新 更多