2016-06-02 11 views
10

起源はキルケにJSONオブジェクトの `ラクダのcase`にunderscore``からすべてのキーを変換

{ 
     "firstName" : "foo", 
     "lastName" : "bar", 
     "parent" : { 
     "firstName" : "baz", 
     "lastName" : "bazz", 
     } 
    } 

がどのように私はJSONオブジェクトのすべてのキーを変換することができ

期待
{ 
    "first_name" : "foo", 
    "last_name" : "bar", 
    "parent" : { 
    "first_name" : "baz", 
    "last_name" : "bazz", 
    } 
} 

+0

「ヘビケース "==キャメルケース? – Thilo

+0

@Thiloはい、そのcamecase – jilen

答えて

10

これは私がこれを書く方法です。それは私が好きなように簡潔ではありませんが、それはひどいではありません。最後に

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) 

そして:

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) 
) 

そして、我々は、おそらく再帰のいくつかの方法を持っている必要があり

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" 
    } 
} 

このようにしてJson => F[Json]変換を適用する方がより便利です。

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) 
     } 
    } 

現在のところ、私はこのように変換しますが、やや複雑です。単純な方法があることを願っています。

0

私は@Travis答えを取り、それを少し近代化、私は彼のコードを取って、私はいくつかのエラーと警告していた、猫1.0.0-MFとScalaの2.12用の更新されたバージョンので:

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 
関連する問題