Compile JsonPath to Monocle optics, pass and use it freely.
- Support filter and function extension.
- Add core dependency.
libraryDependencies ++= Seq(
"io.github.greyplane" %% "jsonpath4s-core" % "version",
"io.github.greyplane" %% "jsonpath4s-optics" % "version"
)
- Add JSON library support as you needed, currently we supported
circe
andspray-json
.
libraryDependencies ++= Seq(
"io.github.greyplane" %% "jsonpath4s-circe" % "version",
// or if you're using spray-json
"io.github.greyplane" %% "jsonpath4s-spray-json" % "version"
)
- If you're using Scala 2, here's the extra config required for Scala 2 to use Scala 3 artifact.
ThisBuild / scalacOptions ++= Seq("-Ytasty-reader")
// add cross config for every artifact
("io.github.greyplane" %% "jsonpath4s-core" % "version").cross(CrossVersion.for2_13Use3)
- Add imports as needed, for typical usage the following should suffice.
import jsonpath4s._
import jsonpath4s.optics._
// if you're using spray-json, import jsonpath4s.json.spray._
import jsonpath4s.json.circe._
if you're using scala 3
import jsonpath4s.*
import jsonpath4s.optics.*
import jsonpath4s.json.circe.given
For simplest usage you could just utilizing the string interpolation functionality.
// This would throw RuntimeException if parsing failed!
val nodeLists: List[Json] = jsonpath"$$.a".compile.getAll(json)
For safer option, you should use JsonPathParser
directly.
val maybeJsonPath: Either[JsonPathError, JsonPath] = JsonPathParser.parse("""$.a""")
If you'd like use one JsonPath multiple times, you could just compile it and pass it around, after all, it's just a normal optic!
// make sure you've import json support library
val a: Fold[Json, Json] = jsonpath"$$.a".compile
Since they're just normal optics, there's nothing prevent you to compose them!
val a = jsonpath"$$.a".compile
val b = jsonpath"$$.b".compile
// it's equivalent to jsonpath"$$.a.b"
a.andThen(b)
// number of Traversal equals to the product of all segments' segment.selectors.size
// in this case there's only 1 Traversal
val ts: Seq[Traversal] = summon[Compiler[Json]].compileSegments(jsonpath"$$.a.*")
// this will modify for example { "a": { "b": 1, "c": 2 } } to { "a": { "b": "test", "c": "test" } }
ts.map(_.modify(_ => Json.fromString("test"))(json))
But there's one gotcha, if your JsonPath contains descendants segment(..
), it cannot be used as setter, since we
use uniplate
's cosmos
combinator, which should be a Fold
rather than Traversal
, but we implemented it as a Traversal
to make use others
as setter possible.