【问题标题】:Scala Play Framework JSON JsNull using json4sScala Play Framework JSON JsNull 使用 json4s
【发布时间】:2015-07-16 18:09:17
【问题描述】:

我是 Scala 新手。如何处理代码中的 JsNull 值?

我正在使用 json4s 将 JSON 转换为地图。 我是否应该以某种方式将JsNull 转换为Option

例子:

播放 JSON:创建 json

val jsonA: JsValue = Json.obj(
      "name" -> "Bob",
      "location" -> "Irvine",
      "resident" -> "No",
      "nick-name" -> "Bigwig",
      "age" -> "6",
      "role" -> JsNull,
      "car" -> "BMW",
      "multiple-residents" -> JsArray(Seq(
        JsObject(Seq(
          "name" -> JsString("Fiver"),
          "age" -> JsNumber(4),
          "role" -> JsObject(Seq(
                      "position" -> JsString("Fiver"),
                      "" -> JsNumber(4),
                      "role" -> JsString("janitor")
                    ))
        ))
      ))
)

json4s : 解析 json

var jsonAMap:Map[String, Any] = Map()
  val jsonAString: String = Json.stringify(jsonA)
  jsonAMap = jsonStrToMap(jsonAString) 

JsValue 使用 json4s 转换为 Map 后看起来像这样:

Map(name -> Bob, location -> Irvine, role -> null, resident -> No, car -> BMW, multiple-residents -> List(Map(name -> Fiver, age -> 4, role -> Map(position -> Fiver,  -> 4, role -> janitor))), age -> 6, nick-name -> Bigwig)

当我创建一个 List 的值时,我最终在我的列表中得到一个 null 值。一旦我对列表的所有值进行模式匹配,我最终会尝试匹配null,这是不可能的(我确定我不应该在所有情况下都使用遗嘱卡,但我米学习):

for(i <- 0 to beforeValsList.length - 1){
  beforeValsList(i) match { 
    case _ : Map[_,_] => 
      compareJson(
        beforeValsList(i).asInstanceOf[Map[String,Any]], 
        afterValsList(i).asInstanceOf[Map[String,Any]], 
        rdeltaBefore, rdeltaAfter, sameKeyList(i).toString()
      )
    case _ if (beforeValsList(i) != afterValsList(i)) => 
      // if i'm from a recursion, build a new map and add me 
      // to the deltas as a key->value pair
      rdeltaBefore += sameKeyList(i).toString -> beforeValsList(i)
      rdeltaAfter += sameKeyList(i).toString -> afterValsList(i)
    case _ => 
      println("catch all: " + beforeValsList(i).toString 
        + " " + afterValsList(i).toString)
  } 
}

json4s 将JsNull 转换为空值。我应该做一个空检查:

if(!beforeValsList(i) == null){
      beforeValsList(i) match{...}
}

或者当我将Map 中的值设置为List 时,是否有办法将null 更改为Option

我不确定最佳实践是什么以及为什么 jsno4s 将 JsNull 更改为 null 而不是 Option,以及这是否可能。

干杯。

【问题讨论】:

  • 你的问题不是很清楚,也许你可以给我们一个更多的concise example你是如何处理JsNull的问题。
  • 获取两个 json 字符串之间差异的简单方法可能是使用 json4s Diff
  • 嗨,彼得,感谢您的评论,我希望我的问题更清晰简洁。我需要的不仅仅是差异。我需要两个增量,除了在我比较的两个 JSON 中相同的键和值之外,它们都可以保存所有内容。我厌倦了寻找一个框架来处理这个问题,但我找不到任何可以按照我需要的方式工作的东西。我也是一名初级程序员,所以我尝试做一些事情来更好地理解 JSON 之类的东西,并思考问题而不是使用框架/函数。感谢您的回复,如果我可以进一步澄清,请告诉我。 :)
  • 您可以使用values.map(Option.apply) 之类的方式将所有值放入Option

标签: json scala playframework json4s


【解决方案1】:

我仍然不确定你想如何处理JsNullnull(或None,如果你使用Option),但你可以得到Map[String, Any]前后的区别可以简化:

type JsonMap = Map[String, Any]

def getMapDiffs(mapBefore: JsonMap, mapAfter: JsonMap) : (JsonMap, JsonMap) = {
  val sameKeys = mapBefore.keySet intersect mapAfter.keySet
  val startAcc = (Map.empty[String, Any], Map.empty[String, Any])
  sameKeys.foldLeft(startAcc){ case (acc @ (deltaBefore, deltaAfter), key) =>
    (mapBefore(key), mapAfter(key)) match {
      // two maps -> add map diff recursively to before diff and after diff
      case (beforeMap: Map[_, _], afterMap: Map[_, _]) =>
        val (deltaB, deltaA) = 
          getMapDiffs(beforeMap.asInstanceOf[JsonMap], afterMap.asInstanceOf[JsonMap])
        (deltaBefore + (key -> deltaB), deltaAfter + (key -> deltaA))
      // values before and after are different
      // add values to before diff and after diff
      case (beforeValue, afterValue) if beforeValue != afterValue =>
        (deltaBefore + (key -> beforeValue), deltaAfter + (key -> afterValue))
      // keep existing diff  
      case _ => acc
    }  
  }
}

可以用作:

val (mapBefore, mapAfter) = (
  Map("a" -> "alpha", "b" -> "beta", "c" -> "gamma", "d" -> Map("e" -> "epsilon")),
  Map("a" -> "alpha", "b" -> List("beta"), "c" -> null, "d" -> Map("e" -> 3))
)

val (deltaBefore, deltaAfter) = getMapDiffs(mapBefore, mapAfter)
// deltaBefore: JsonMap = Map(b -> beta, c -> gamma, d -> Map(e -> epsilon))
// deltaAfter: JsonMap = Map(b -> List(beta), c -> null, d -> Map(e -> 3))

deltaBefore.toList
// List[(String, Any)] = List((b,beta), (c,gamma), (d,Map(e -> epsilon)))

【讨论】:

  • 彼得,哇。我如何学习 Scala 才能像你刚才那样思考问题并解决它,我一周半前才开始使用 Scala。我拿起了 Alvin Alexander 的 Scala Cookbook,但我不确定学习 Scala 的正确方法。你能为我指出正确的方向吗?你写得这么快,我惊呆了。感谢您提供的功能,我将阅读我的代码并尝试完全理解您的解决方案。
  • @krzasteka 阅读您选择的一些 Scala 书籍,并尝试以功能性/Scala 惯用方式解决问题、练习等,但请放心,这需要大多数人一些时间习惯函数式编程。祝你好运!
  • 再次感谢!干杯:)
猜你喜欢
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-10
  • 1970-01-01
相关资源
最近更新 更多