用1个元素解析Json List(Scala/liftweb)



我遇到了从外部服务器检索Json的情况(我无法控制该服务器)。Json有一个元素,可能出现1次或多次。我正在尝试使用net.liftweb.json工具来解析它,只有当元素出现多次时,它才能正常工作。如果元素只出现一次,则无法解析。

下面是一些示例代码:

import net.liftweb.json._
import net.liftweb.json.JsonDSL._
case class JSonListIssue(foo: List[String])
class JSonTest extends TestCase {
implicit val formats = net.liftweb.json.DefaultFormats; 
def testJsonList {
val jsonStr2Foos = "{"foo": "bar", "foo": "bar2"}"
val json = (parse(jsonStr2Foos).extract[JSonListIssue]) 
assertEquals(2, json.foo.size)
val jsonStr1Foo = "{"foo": "bar"}"
val json2 = (parse(jsonStr1Foo).extract[JSonListIssue]) // Results in Json MappingException
assertEquals(1, json2.foo.size)
}
}

上述代码中的第二个解析语句失败。如果我按如下方式定义case类,那么第二个解析会起作用,但第一个解析会失败。

case class JSonListIssue(foo: String)

关于如何以干净的方式解决这个问题,有什么建议吗?当然,我可以捕获MappingException,然后使用其他case类对其进行解析,但那太脏了。。。

谢谢,Gero

所以,首先,虽然你无法控制写API的人,但如果你遇到他们,一定要因为他们做了这样愚蠢的事情而向他们开枪。:P

所以,这不是世界上最干净的解决方案,但我想我想出了一些对你有用的方法。可以使用运算符直接查询通过解析JSON生成的JValue。

所以,像这样的东西应该对你有用。

case class JsonListIssue(foo: List[String])
def extractJsonListIssue(json: JValue) = {
json  "foo" match {
case JString(foo) =>
JsonListIssue(List(foo))
case _ =>
json.extract[JsonListIssue]
}
}

您可能需要也可能不需要json "foo"周围的parens来编译它。但是我认为这在大多数情况下都适用。FWIW,如果你想成为真正的Lift-y,你应该认真考虑在这里使用Box,并使用tryo将提取中的任何异常转化为Failure,你可以在调用堆栈中更高级别捕捉到它。所以,看起来像这样:

// Add these guys to your existing imports
import net.liftweb._
import common._
import util.Helpers._
case class JsonListIssue(foo: List[String])
def extractJsonListIssue(json: JValue) = {
json  "foo" match {
case JString(foo) =>
Full(JsonListIssue(List(foo)))
case _ =>
// Will return a Full with the result of the method on
// success and a Failure if extract throws an exception.
tryo(json.extract[JsonListIssue])
}
}

然后,您可以在中使用它来理解代码中的其他部分。

如果这不起作用,请告诉我。如果我有什么更干净的事,我会告诉你的。干杯,伙计!

最新更新