簡體   English   中英

使用 play Json 庫(或任何其他建議)在多級數組上使用 JsLookup

[英]JsLookup on multiple level array using play Json library (or any other suggestion)

我的函數正在接收一個JsValue ,現在這個 json 有列表,這個列表元素也可以是列表,例如:

{
  "firstName": "Elon",
  "lastName": "Musk",
  "companies": [
    {
      "name": "Tesla",
      "city": "San Francisco",
      "offices": ["sf", "ny"],
      "management": {
        "loscation": "New York",
        "boardMembers": [
          {
            "name": "John",
            "age": 45
          },
          {
            "name": "Mike",
            "age": 55
          },
          {
            "name": "Rebecca",
            "age": 35
          }
        ]
      }
    },
    {
      "name": "SpaceX",
      "city": "San Francisco",
      "offices": ["la", "ta"],
      "management": {
        "loscation": "San Mateo",
        "boardMembers": [
          {
            "name": "Lisa",
            "age": 45
          },
          {
            "name": "Dan",
            "age": 55
          },
          {
            "name": "Henry",
            "age": 35
          }
        ]
      }
    }
  ]
}

所以一個公司有管理對象,其中有 boardMembers 列表。

我的函數正在接收該元素的路徑,例如:

companies[*].management.boardMembers[*].name

我希望它返回一個包含此對象所有元素的列表,因此結果將是:

["John", "Mike", "Rebecca", "Lisa", "Dan", "Henry"]

這有點復雜,但我認為play.api.libs.json._可能會有一些play.api.libs.json._功能。

考慮拆分它pathStr.split("(\\\\[\\\\*]\\\\.|\\\\[\\\\*])").toList然后迭代以獲取所有元素的一些方法並返回 JsLookupResult 但不確定如何。

只是為了澄清:

我的方法將接收 2 個參數, JsValue和作為字符串的路徑def myFunc(json: JsValue, path: String)

每次我調用myFunc它都會收到不同的路徑,我不確定只有在調用myFunc之后它會是什么。

正如您在文檔中所見,您可以使用Reads類型類來定義從 JSON 解碼類型的方式。

import play.api.libs.json._

val input = """{
  "firstName": "Elon",
  "lastName": "Musk",
  "companies": [
    {
      "name": "Tesla",
      "city": "San Francisco",
      "offices": ["sf","ny"],
      "management": {
        "loscation": "New York",
        "boardMembers": [
          {
            "name": "John",
            "age": 45
          },
          {
            "name": "Mike",
            "age": 55
          },
          {
            "name": "Rebecca",
            "age": 35
          }
        ]
      }
    },
    {
      "name": "SpaceX",
      "city": "San Francisco",
      "offices": ["la","ta"],
      "management": {
        "loscation": "San Mateo",
        "boardMembers": [
          {
            "name": "Lisa",
            "age": 45
          },
          {
            "name": "Dan",
            "age": 55
          },
          {
            "name": "Henry",
            "age": 35
          }
        ]
      }
    }
  ]
}"""

val json = Json.parse(input)

// ---

case class BoardMember(name: String, age: Int)

implicit val br: Reads[BoardMember] = Json.reads

case class Company(boardMembers: Seq[BoardMember])

implicit val cr: Reads[Company] = Reads {
  case obj @ JsObject(_) =>
    (obj \ "management" \ "boardMembers").validate[Seq[BoardMember]].map {
      Company(_)
    }

  case _ =>
    JsError("error.obj.expected")
}

val reads = Reads[Seq[String]] {
  case obj @ JsObject(_) =>
    (obj \ "companies").validate[Seq[Company]].map {
      _.flatMap(_.boardMembers.map(_.name))
    }

  case _ =>
    JsError("error.obj.expected")
}

// ---

json.validate(reads)
//  play.api.libs.json.JsResult[Seq[String]] = JsSuccess(Vector(John, Mike, Rebecca, Lisa, Dan, Henry),)

你可以做:

val jsPath = JsPath \ "companies" \\ "management" \ "boardMembers" \\ "name"
val result = jsPath(Json.parse(input))
println(result)

這將打印預期的輸出。 參見Scastie示例。

請注意\\\\\\之間的區別:

  • \\尋找直系子女
  • \\\\尋找遞歸子節點

要實現myFunc您可以嘗試以下操作:

def findAllValuesAtPath(jsValue: JsValue, path: String): List[JsValue] = {
  val jsPath = JsPath(path
    .split("\\[\\*]\\.")
    .flatMap(s => s.split("\\.")
      .map(RecursiveSearch)
    ).toList)
  println(jsPath.path)
  jsPath(jsValue)
}

是另一個scastie。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM