Scala 使用Play JSON查询并查找JSON元素值的路径

Scala 使用Play JSON查询并查找JSON元素值的路径,scala,playframework,jsonpath,Scala,Playframework,Jsonpath,我将Play框架与Scala一起使用。对于上游服务器返回的JSON,我有以下结构。这只是一种表述 { "key": "some-key", "suspendData": { "d": [ [ "arbitrary-objects/strings" ], [ "random-value", [ "arbitrary-objects/strings" ],

我将Play框架与Scala一起使用。对于上游服务器返回的JSON,我有以下结构。这只是一种表述

{
  "key": "some-key",
  "suspendData": {
    "d": [
      [
        "arbitrary-objects/strings"
      ],
      [
        "random-value",
        [
          "arbitrary-objects/strings"
        ],
        [
          [
            "value1",
            "important-item",
            [
              "important-key-1"
            ],
            "arbitrary-values/objects"
          ],
          [
            "value2",
            "important-item-2",
            [
              "important-key-2"
            ]
          ]
        ]
      ]
    ]
  }
}
我所掌握的唯一事实是,数据将位于
$.suspendData.d[1]
中的某个位置。我知道我正在搜索的值是
important-key-1
。该值可以嵌套得更深,也可以位于`d[1]中的其他索引上。我如何处理发现

  • 密钥存在于从上游服务器获得的JSON中
  • 找到密钥的路径,因此我可以基于同一路径找到其他密钥。这是一个反向查找问题
  • 我目前只能考虑获取
    $.suspendData.d[1]
    ,然后循环查找是否存在此类属性。
    再一次,我找不到通过JsPath实现这一点的正确方法。我知道JsonPath等价物,但无法通过现有的Play JSON支持找到正确的方法。

    您可以使用
    JsValue
    上定义的
    \
    方法,导航到JSON中您想要的位置

    要获取您想要的内容,请执行以下操作:
    ((json\'suspendData')\'d”)(1)

    以下是相同的REPL输出

    scala> val json = Json.parse(str) 
    json: JsValue = {"key":"some-key","suspendData":{"d":[["arbitrary-objects/strings"],["random-value",["arbitrary-objects/strings"],[["value1","important-item",["important-key-1"],"arbitrary-values/objects"],["value2","important-item-2",["important-key-2"]]]]]}}
    
    scala> ((json \ "suspendData") \ "d")(1) 
    res32: JsLookupResult = JsDefined(
      ["random-value",["arbitrary-objects/strings"],[["value1","important-item",["important-key-1"],"arbitrary-values/objects"],["value2","important-item-2",["important-key-2"]]]]
    )
    
    scala> val json = Json.parse(str) 
    json: JsValue = {"key":"some-key","suspendData":{"d":[["arbitrary-objects/strings"],["random-value",["arbitrary-objects/strings"],[["value1","important-item",["important-key-1"],"arbitrary-values/objects"],["value2","important-item-2",["important-key-2"]]]]]}}
    
    scala> (json \ "suspendData") 
    res34: JsLookupResult = JsDefined(
      {"d":[["arbitrary-objects/strings"],["random-value",["arbitrary-objects/strings"],[["value1","important-item",["important-key-1"],"arbitrary-values/objects"],["value2","important-item-2",["important-key-2"]]]]]}
    )
    
    scala> (json \ "suspendData") \ "d" 
    res35: JsLookupResult = JsDefined(
      [["arbitrary-objects/strings"],["random-value",["arbitrary-objects/strings"],[["value1","important-item",["important-key-1"],"arbitrary-values/objects"],["value2","important-item-2",["important-key-2"]]]]]
    )
    
    scala> ((json \ "suspendData") \ "d")(0) 
    res36: JsLookupResult = JsDefined(["arbitrary-objects/strings"])
    
    scala> ((json \ "suspendData") \ "d")(1) 
    res37: JsLookupResult = JsDefined(
      ["random-value",["arbitrary-objects/strings"],[["value1","important-item",["important-key-1"],"arbitrary-values/objects"],["value2","important-item-2",["important-key-2"]]]]
    )
    

    简单递归,可能不太有效,但有效:

    def findPath(key: String, path: JsPath, xs: JsValue): Option[JsPath] = {
      xs match {
        case o:JsObject =>
          var res: Option[JsPath] = None
          val it = o.fields.iterator
          while (res.isEmpty && it.hasNext) {
            val e = it.next()
            res = findPath(key, path \ (e._1), e._2)
          }
          res
        case JsString(x) if x==key => 
          Some(path)
        case JsArray(x) =>
          var res: Option[JsPath] = None
          val it = x.zipWithIndex.iterator
          while (res.isEmpty && it.hasNext) {
            val e = it.next()
            res = findPath(key, path(e._2), e._1)
          }
          res
        case _ => None
      }
    }
    
    findPath("important-key-1", __, j)
    findPath("important-key-2", __, j)
    findPath("important-key-3", __, j)
    findPath("some-key", __, j)
    
    scala> res62: Option[play.api.libs.json.JsPath] = Some(/suspendData/d(1)(2)(0)(2)(0))
    
    scala> res63: Option[play.api.libs.json.JsPath] = Some(/suspendData/d(1)(2)(1)(2)(0))
    
    scala> res64: Option[play.api.libs.json.JsPath] = None
    
    scala> res65: Option[play.api.libs.json.JsPath] = Some(/key)
    

    +1这部分回答了与JsPath相关的问题,但我的主要问题是确定应该使用哪条路径。所以,我需要一个反向查找。找到一个特定值并确定可用于达到该值的路径。以有效的方式。不确定是否有效,但至少它帮助我前进!