我能否使用Scala的lift-json库将JSON解析为Map?

15
有没有办法使用lift-json库的JObject类来像Map一样操作?
例如:
val json = """
{ "_id" : { "$oid" : "4ca63596ae65a71dd376938e"} , "foo" : "bar" , "size" : 5}
"""

val record = JsonParser.parse(json)
record: net.liftweb.json.JsonAST.JValue = JObject(List(JField(_id,JObject(List(JField($oid,JString(4ca63596ae65a71dd376938e))))), JField(foo,JString(bar)), JField(size,JInt(5))))

</code>
我希望 record("foo") 返回 "bar"。
我注意到有一个 values 函数,它打印出一个 Map,但实际对象是 JValue.this.Values?
示例代码如下:
scala> record.values res43: record.Values = Map((_id,Map($oid -> 4ca63596ae65a71dd376938e)), (foo,bar), (size,5))
scala> record.values("foo") :12: error: record.values of type record.Values does not take parameters record.values("foo")
在 lift-json 库中,有提取 case class 的案例,但在这种情况下,我不知道 JSON 模式。

这是一个相关的答案,用于解析Map作为案例类中的参数https://dev59.com/LVTTa4cB1Zd3GeqPsnu7#6310493 - tommy chheng
2个回答

14

如果你查看实现,你会发现

case class JObject(obj: List[JField]) extends JValue {
  type Values = Map[String, Any]
  def values = Map() ++ obj.map(_.values.asInstanceOf[(String, Any)]) // FIXME compiler fails if cast is removed
}

所以这应该有效:

record.values.asInstanceOf[Map[String, Any]]("foo")

你也可以尝试

record.values.apply("foo")

谢谢,第一个方法可行,使用apply()的第二个选项会返回错误。我最终使用了Scala内置的Java解析器。scala.util.parsing.json.JSON.parseFull(record)将返回Some(Map)或Some(List)。 - tommy chheng

7

JValue.Values是一种路径依赖类型。这意味着,如果您持有JString,则它将是一个字符串,或者如果您获得了JArray,则它将是List[Any]。如果您确定解析的JSON是JSON对象,则可以将其转换为适当的类型。

val record = JsonParser.parse(json).asInstanceOf[JObject]

JObject 的路径依赖类型是 Map[String, Any],因此:
scala> record.values("foo")                                     
res0: Any = bar

只是好奇,如果您不知道要解析的数据的形状,这不是有点棘手吗?

请注意,如果您的数据包含(名称、描述、年龄),而年龄是可选的,您可以将该JSON读入:

case class Person(name: String, description: String, age: Option[Int])

我有一个JSON,其中包含不同字段的数组。例如,第一个文档可能具有(名称、描述、年龄),但第二个文档可能只指定了(名称、年龄)。如果我使用Scala的Map对象,我可以调用document.getOrElse("foo", "")。 - tommy chheng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接