使用 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
我希望它 return 包含此对象的所有元素的列表,因此结果将是:
["John", "Mike", "Rebecca", "Lisa", "Dan", "Henry"]
有点复杂,但我想 play.api.libs.json._
可能会有一些可以提供帮助的功能。
考虑过拆分它 pathStr.split("(\[\*]\.|\[\*])").toList
然后迭代以获取所有元素一些如何和 return 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)
}
Here 是另一个 scastie。
我的函数正在接收一个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
我希望它 return 包含此对象的所有元素的列表,因此结果将是:
["John", "Mike", "Rebecca", "Lisa", "Dan", "Henry"]
有点复杂,但我想 play.api.libs.json._
可能会有一些可以提供帮助的功能。
考虑过拆分它 pathStr.split("(\[\*]\.|\[\*])").toList
然后迭代以获取所有元素一些如何和 return 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)
}
Here 是另一个 scastie。