2016-06-02 5 views
10

ПроисхождениеTransform все ключи от `` underscore` к верблюжьей case` объектов JSon в Цирцеи

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

Ожидаемое

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

Как я могу преобразовать все ключи объектов JSon?

+0

«змея case "== CamelCase? – Thilo

+0

@ Тило Да, его камера – jilen

ответ

10

Вот как я это написал. Это не настолько кратким, как хотелось бы, но это не страшно:

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

И потом:

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) 

И наконец:

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 ответ и модернизирована его немного, я взял свой код и у меня было несколько ошибок и предупреждений, поэтому обновленную версию для Scala 2.12 с кошками 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 

 Смежные вопросы

  • Нет связанных вопросов^_^