Scala utility to recursively traverse and transform json like tree structure made of Lists and Maps
There is no maven artifact published jet. One way how to add this project is to add direct dependency to github repo in build file
build.sbt:
lazy val p = project.
dependsOn(uri("git://github.com/muntis/scala-recursive-map"))
or project/Build.scala:
lazy val p = Project(id = "project" ...).
dependsOn(uri("git://github.com/muntis/scala-recursive-map"))
import org.recmap.MapRecursiveExtensions._
tree.recursiveMap{
// partial transformation function
}
Partial function signature:
((path: Any, value: Any)) => newValue: Any
To unleash full power of scala matcher, path is case class created by "/" operand. Path nodes are strings for map keys and integers for list indexes.
Let's consider structure
val department = Map(
"name" -> "Sales",
"employees" -> List(
Map("name" -> "Bob", "surname"-> "Smith", "salary" -> BigDecimal(1000.00)),
Map("name" -> "Mary", "surname"-> "Jones", "salary" -> BigDecimal(1700.10))
)
)
Partial function will be called with values:
("name", "Sales")
("employees", List(Map("name" -> "Bob", "surname" -> "Smith", "salary" -> BigDecimal(1000.0)), Map("name" -> "Mary", "surname" -> "Jones", "salary" -> BigDecimal(1700.1))))
("employees" / 0, Map("name" -> "Bob", "surname" -> "Smith", "salary" -> BigDecimal(1000.0)))
("employees" / 0 / "name", "Bob")
("employees" / 0 / "surname", "Smith")
("employees" / 0 / "salary", BigDecimal(1000.0))
("employees" / 1, Map("name" -> "Mary", "surname" -> "Jones", "salary" -> BigDecimal(1700.1)))
("employees" / 1 / "name", "Mary")
("employees" / 1 / "surname", "Jones")
("employees" / 1 / "salary", BigDecimal(1700.1))
Transformations:
Adding index to employee:
department.recursiveMap{
case ("employees" / index, employee: Map[String, Any]) => employee + ("index" -> index)
}
// Result:
// Map(name -> Sales, employees -> List(
// Map(name -> Bob, surname -> Smith, salary -> 1000.0, index -> 0),
// Map(name -> Mary, surname -> Jones, salary -> 1700.1, index -> 1)
// ))
Employee name/surname to lower case:
department.recursiveMap{
case ("employees" / _ / ("name"| "surname"), name: String) => name.toLowerCase
}
// Result:
// Map(name -> Sales, employees -> List(
// Map(name -> bob, surname -> smith, salary -> 1000.0),
// Map(name -> mary, surname -> jones, salary -> 1700.1)
// ))
Change types of tree leaves (I'm looking at you MongoDb):
department.recursiveMap{
case (_, bd: BigDecimal) => "Now as string: "+bd.toString
}
// Result:
// Map(name -> Sales, employees -> List(
// Map(name -> Bob, surname -> Smith, salary -> Now as string: 1000.0),
// Map(name -> Mary, surname -> Jones, salary -> Now as string: 1700.1)
// ))
Or mix them all in one transformation:
department.recursiveMap{
case ("employees" / index, employee: Map[String, Any]) => employee + ("index" -> index)
case ("employees" / _ / ("name"| "surname"), name: String) => name.toLowerCase
case (_, bd: BigDecimal) => "Now as string: "+bd.toString
}
// Result:
// Map(name -> Sales, employees -> List(
// Map(name -> bob, surname -> smith, salary -> Now as string: 1000.0, index -> 0),
// Map(name -> mary, surname -> jones, salary -> Now as string: 1700.1, index -> 1)
// ))