Skip to content

philwills/json4s-zipper

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

json4s-zipper

This is an experimental zipper library for the json4s AST.

The goal of this library is to implement purely functional modifications to immutable JSON structures.

Examples

This library depends on json4s-core, not on any of the json4s parsing libraries. To follow these examples, you'll need a project that depends on json4s-native or json4s-jackson. (Or, you'll need to construct the JSON example by hand using the AST.)

The tests for json4s-zipper use the native parser, so if you have SBT installed, and a copy of the source, you can run sbt test:console to try these examples.

To start with, here is some JSON, parsed into the JValue AST.

import org.json4s.native.JsonMethods._

val json = parse("""{"soups":["goulash","gumbo","minestrone"]}""")

XPath-style syntax

This library has support for modifying elements of a JSON structure using an xpath-like syntax.

import com.gu.json.syntax._
import org.json4s.JsonAST._

// Append the string " is tasty!" to each string in the array within the field "soups"
val tastySoups = json.mod ("soups" \ *) { case JString(s) => JString(s + " is tasty!") }

println(compact(render(tastySoups)))
// {"soups":["goulash is tasty!","gumbo is tasty!","minestrone is tasty!"]}

Basic Cursor API

It's a little verbose, but you can use the JCursor API directly. Most operations result in an Option[JCursor], as they may fail (e.g. if you use field when the focus is on a JArray).

val cursor = json.cursor // Create a cursor focusing on the root of the `JValue`

val updatedCursor = for {
  a <- cursor.field("soups")         // Go to field "soups"
  b <- a.prepend(JString("borscht")) // Prepend to the array
} yield b

for (c <- updatedCursor) println(compact(render(c.toJson)))
// {"soups":["borscht","goulash","gumbo","minestrone"]}

Lenses

Lenses enable bidirectional transformations on data structures; i.e. the ability to query and update a view of the structure, with modifications propagating back as changes to the original structure.

This library implements Scalaz partial lenses for JValue structures. The get and putback operations are implemented using the cursor API, but lenses provide a more composable API, with a whole host of lens-related operations for free.

The partiality of the lenses is a result of the potential absence of expected elements in the JValue structure. Get and set operations return an Option, and modify operations which fail will return the original structure unmodified.

import com.gu.json.Lenses._

// A partial lens focusing on the string value of the 2nd element of field "soups"
val pLens = field("soups") >=> elem(1) >=> strVal

// The lens can be used simply to view the value at that location
pLens get json
// Some(gumbo)

// The lens can also be used to transform the value
val updatedJson = pLens mod ("shellfish " + _, json)

println(compact(render(updatedJson)))
// {"soups":["goulash","shellfish gumbo","minestrone"]}

See LensExamples for more examples.

About

Experimental zipper library for the json4s AST

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published