2016-06-02 10 views

risposta

10

Ecco come scriverei questo. Non è così conciso come vorrei, ma non è terribile:

import cats.free.Trampoline 
import cats.std.list._ 
import cats.syntax.traverse._ 
import io.circe.{ Json, JsonObject } 

/** 
* Helper method that transforms a single layer. 
*/ 
def transformObjectKeys(obj: JsonObject, f: String => String): JsonObject = 
    JsonObject.fromIterable(
    obj.toList.map { 
     case (k, v) => f(k) -> v 
    } 
) 

def transformKeys(json: Json, f: String => String): Trampoline[Json] = 
    json.arrayOrObject(
    Trampoline.done(json), 
    _.traverse(j => Trampoline.suspend(transformKeys(j, f))).map(Json.fromValues), 
    transformObjectKeys(_, f).traverse(obj => Trampoline.suspend(transformKeys(obj, f))).map(Json.fromJsonObject) 
) 

E poi:

import io.circe.literal._ 

val doc = json""" 
{ 
    "first_name" : "foo", 
    "last_name" : "bar", 
    "parent" : { 
    "first_name" : "baz", 
    "last_name" : "bazz" 
    } 
} 
""" 

def sc2cc(in: String) = "_([a-z\\d])".r.replaceAllIn(in, _.group(1).toUpperCase) 

E infine:

scala> import cats.std.function._ 
import cats.std.function._ 

scala> transformKeys(doc, sc2cc).run 
res0: io.circe.Json = 
{ 
    "firstName" : "foo", 
    "lastName" : "bar", 
    "parent" : { 
    "firstName" : "baz", 
    "lastName" : "bazz" 
    } 
} 

Probabilmente dovremmo avere qualche modo di modo ricorsivo applicare una trasformazione Json => F[Json] in questo modo più conveniente.

1
def transformKeys(json: Json, f: String => String): TailRec[Json] = { 
     if(json.isObject) { 
     val obj = json.asObject.get 
     val fields = obj.toList.foldLeft(done(List.empty[(String, Json)])) { (r, kv) => 
      val (k, v) = kv 
      for { 
      fs <- r 
      fv <- tailcall(transformKeys(v, f)) 
      } yield fs :+ (f(k) -> fv) 
     } 
     fields.map(fs => Json.obj(fs: _*)) 
     } else if(json.isArray) { 
     val arr = json.asArray.get 
     val vsRec = arr.foldLeft(done(List.empty[Json])) { (vs, v) => 
      for { 
      s <- vs 
      e <- tailcall(transformKeys(v, f)) 
      } yield s :+ e 
     } 
     vsRec.map(vs => Json.arr(vs: _*)) 
     } else { 
     done(json) 
     } 
    } 

Attualmente mi fanno trasformare in questo modo, ma è piuttosto complicato, spero che ci sia un modo semplice.

0

ho preso @Travis risposta e modernizzato un po ', ho preso il suo codice e ho avuto diversi errori e le avvertenze, così la versione aggiornata per Scala 2.12 con i gatti 1.0.0-MF:

import io.circe.literal._ 
import cats.free.Trampoline, cats.instances.list._, cats.instances.function._, cats.syntax.traverse._, cats.instances.option._ 

def transformKeys(json: Json, f: String => String): Trampoline[Json] = { 
    def transformObjectKeys(obj: JsonObject, f: String => String): JsonObject = 
    JsonObject.fromIterable(
     obj.toList.map { 
     case (k, v) => f(k) -> v 
     } 
    ) 
    json.arrayOrObject(
    Trampoline.done(json), 
    _.toList.traverse(j => Trampoline.defer(transformKeys(j, f))).map(Json.fromValues(_)), 
    transformObjectKeys(_, f).traverse(obj => Trampoline.defer(transformKeys(obj, f))).map(Json.fromJsonObject) 
) 
} 

def sc2cc(in: String) = "_([a-z\\d])".r.replaceAllIn(in, _.group(1).toUpperCase) 

def camelizeKeys(json: io.circe.Json) = transformKeys(json, sc2cc).run 
Problemi correlati