Scala:在嵌套映射中查找值(从JSON解析)

时间:2017-05-23 15:08:17

标签: json scala

我将JSON转换为非常复杂的嵌套映射。 我只需要这张地图中的一个值。它是领域“系统”。 在我的示例中,值为“DEV130PHYSTEST”。 任何人都可以帮我在这张地图中用Scala找到这个值吗?

Some(Map(type -> SUCCESS, msg -> Container D4SContRules successfully called., result -> Map(execution-results -> Map(results -> List(Map(key -> , value -> 1.0), Map(key -> output, value -> List(Map(demo.d4srules.inputObj -> Map(order -> 1.0)), Map(demo.d4srules.outputObj -> Map(system -> DEV130PHYSTEST)))), Map(key -> input, value -> Map(demo.d4srules.inputObj -> Map(order -> 1.0)))), facts -> List(Map(key -> input, value -> Map(org.drools.core.common.DefaultFactHandle -> Map(external-form -> 0:1:1400441403:1400441403:1:DEFAULT:NON_TRAIT:demo.d4srules.inputObj))))))))

作为替代方案,我们也可以从JSON开始:

{
    "type": "SUCCESS",
    "msg": "Container D4SContRules successfully called.",
    "result": {
        "execution-results": {
            "results": [{
                    "key": "",
                    "value": 1
                },
                {
                    "key": "output",
                    "value": [{
                            "demo.d4srules.inputObj": {
                                "order": 1
                            }
                        },
                        {
                            "demo.d4srules.outputObj": {
                                "system": "DEV130PHYSTEST"
                            }
                        }
                    ]
                },
                {
                    "key": "input",
                    "value": {
                        "demo.d4srules.inputObj": {
                            "order": 1
                        }
                    }
                }
            ],
            "facts": [{
                "key": "input",
                "value": {
                    "org.drools.core.common.DefaultFactHandle": {
                        "external-form": "0:1:1640380:1640380:1:DEFAULT:NON_TRAIT:demo.d4srules.inputObj"
                    }
                }
            }]
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我不确定我理解你的问题,但是如果我理解正确的话,你想要的是找到存储在Map中的一个键的值的某种方法,这个键可能在一些复杂的内部深处分层数据结构,你不知道或不想硬编码它的路径。如果是这种情况,您可以尝试这样的事情:

def findValueForKeyDeep[Key](container: Any, key: Key): Option[Any] = {
  @tailrec
  def findValueForKeyInTraversable(tr: Traversable[_], key: Key): Option[Any] = {
    if (tr.isEmpty) None
    else {
      val headRes = findValueForKeyDeep(tr.head, key)
      if (headRes.isDefined) headRes else findValueForKeyInTraversable(tr.tail, key)
    }
  }

  container match {
    case m: scala.collection.Map[Key, _] => m.get(key).orElse(findValueForKeyInTraversable(m.values, key))
    case o: Option[_] => o.flatMap(findValueForKeyDeep(_, key))
    case tr: Traversable[_] => findValueForKeyInTraversable(tr, key)
    case _ => None
  }
}

示例:

val jsonObj = Some(Map(
  "type" -> "SUCCESS",
  "msg" -> "Container D4SContRules successfully called.",
  "result" ->
    Map(
      "execution-results" ->
        Map(
          "results" -> List(
            Map(
              "key" -> "",
              "value" -> 1.0),
            Map(
              "key" -> "output",
              "value" -> List(
                Map("demo.d4srules.inputObj" -> Map("order" -> 1.0)),
                Map("demo.d4srules.outputObj" -> Map("system" -> "DEV130PHYSTEST")))),
            Map(
              "key" -> "input",
              "value" -> Map("demo.d4srules.inputObj" -> Map("order" -> 1.0)))),
          "facts" -> List(
            Map("key" -> "input",
              "value" -> Map("org.drools.core.common.DefaultFactHandle" -> Map("external-form" -> "0:1:1400441403:1400441403:1:DEFAULT:NON_TRAIT:demo.d4srules.inputObj"))))))))

println(findValueForKeyDeep(jsonObj, "system"))
println(findValueForKeyDeep(jsonObj, "external-form"))
println(findValueForKeyDeep(jsonObj, "value"))
println(findValueForKeyDeep(jsonObj, "order"))
println(findValueForKeyDeep(jsonObj, "bad key"))
  

部分(DEV130PHYSTEST)
  一些(0:1:1400441403:1400441403:1:DEFAULT:NON_TRAIT:demo.d4srules.inputObj)
  一些(1.0)
  一些(1.0)
  没有

请注意,如果有多个匹配的键,则此代码返回其中一些键的值(任意)。另请注意,返回类型为Option[Any]但如果您确定实际类型,则可以在调用后使用asInstanceOf强制转换为该类型。

更新(找到所有匹配的值)

如果您想获得所有值,可以轻松完成

  def findAllValuesForKeyDeep[Key](container: Any, key: Key): List[Any] = {
    @tailrec
    def findAllValuesForKeyDeepImpl(container: Any, key: Key, acc: List[Any]): List[Any] = {
      container match {
        case m: scala.collection.Map[Key, _] => {
          val valueOption = m.get(key)
          if (valueOption.isDefined)
            valueOption.get :: acc
          else
            findAllValuesForKeyDeepImpl(m.values, key, acc)
        }
        case Some(v) => findAllValuesForKeyDeepImpl(v, key, acc)
        case tr: Traversable[_] => findAllValuesForKeyInTraversable(tr, key, acc)
        case _ => acc
      }
    }

    @tailrec
    def findAllValuesForKeyInTraversable(tr: Traversable[_], key: Key, acc: List[Any]): List[Any] = {
      if (tr.isEmpty) acc
      else {
        val headAcc = findAllValuesForKeyDeepImpl(tr.head, key, acc)
        findAllValuesForKeyInTraversable(tr.tail, key, headAcc)
      }
    }

    findAllValuesForKeyDeepImpl(container, key, List.empty[Any])
  }

但请注意,现在您不能简单地将List[Any]转换为更具体的内容,如果您确定知道所有元素的类型且它们是相同的,请使用map转换值比如

findAllValuesForKeyDeep(jsonObj, "order").map(v => v.asInstanceOf[Double])