我得到了(示例)JSON:
{
"version": 1.1,
"author": "XYZ",
"elements": [{
"type": "nodeX",
"id": 1,
"a": 1,
"b": 2
},
{
"type": "nodeX",
"id": 2,
"a": 1,
"b": 2
},
...
{
"type": "nodeX",
"id": 13214,
"a": 1,
"b": 2
},
{
"type": "nodeY",
"id": 1,
"c": [
"qaz",
"wsx"
]
},
{
"type": "nodeY",
"id": 2,
"c": [
"qaz",
"wsx"
]
},
...
{
"type": "nodeY",
"id": 3,
"c": [
"qaz",
"wsx"
]
}
]
}
元素列表始终包含具有2种可能性的对象:
- 类型" nodex "和属性: id , a 和 b 。。
- 类型" nodey "和属性: id 和 c 。
我想获得给定类的两个列表:
case class NodeX(val id:Long, val a:Long, val b:Long)
case class NodeY(val id:Long, val c:List[String])
我尝试过CIRCE(Scala库)将此JSON分析到类:
case class Element(val 'type':String, val id:Long, val a:Option[Long],val b:Option[Long], val c:Option[List[String]])
case class MyJson(val version:Double, val author:String, val elements:List[Element])
,但不幸的是我得到了带有可选字段的对象元素列表。
目前,我将其用作解决方法:
val elements = // MyJson.elements
for (elem <- elements)
elem match {
case Element("nodeX", _,_,_,_) => //here convert to NodeX and add to list List[NodeX]
case Element("nodeY", _,_,_,_) => //here convert to NodeY and add to list List[NodeY]
}
我正在寻找更好的解决方案,更快的解决方案,因为此json中的列表包含不少于70k的元素。
预先感谢:)
另一种方法是 dynamic Circe
Monocle
中的scala,它为您提供了不安全的灵活性动态语言:
libraryDependencies += "io.circe" %% "circe-optics" % circeVersion
import io.circe.optics.JsonPath._
import io.circe.parser
val json = parser.parse(jsonString).right.get
case class NodeX(val id:Long, val a:Long, val b:Long)
case class NodeY(val id:Long, val c:List[String])
val nodexs = root.elements.each
.filter(root.`type`.string.getOption(_).contains("nodeX"))
.as[NodeX].getAll(json)
//res: List[NodeX] = List(NodeX(1L, 1L, 2L), NodeX(2L, 1L, 2L))
val nodeys = root.elements.each
.filter(root.`type`.string.getOption(_).contains("nodeY"))
.as[NodeY].getAll(json)
//res: List[NodeY] = List(NodeY(3L, List("qaz", "wsx")))
我相信circe-generic
自动模式可以做同样的事情,而Andriy Plokhotnyuk的答案中描述的是。
如果允许您将NodeX
和NodeY
类定义为具有密封特征的ADT,则可以轻松地通过JSONITER-SCALA解析。
将库添加到您的依赖项列表
libraryDependencies ++= Seq(
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "0.29.2" % Compile,
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "0.29.2" % Provided // required only in compile-time
)
定义您的案例类:
sealed trait Node
final case class NodeX(val id:Long, val a:Long, val b:Long) extends Node
final case class NodeY(val id:Long, val c:List[String]) extends Node
case class MyJson(val version:Double, val author:String, val elements:List[Node])
生成root案例类的编解码器并使用
import java.io._
import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._
val myJsonCodec = JsonCodecMaker.make[MyJson](CodecMakerConfig())
val myJson = {
val fin = new FileInputStream("/tmp/my.json")
try readFromStream(codec, fin)
finally fin.close()
}