2017-02-02 2 views
2

Мне нужно записать значения int json и изменить его на строковое значение с помощью определенной таблицы сопоставлений. Я использую Цирцея, я знал, как изменить значение без изменения типа значения, например:Как изменить тип значения json через Circe

package com.accenture.soh.driver 

import io.circe._, io.circe.parser._ 
import cats.syntax.either._ 
import io.circe._, io.circe.parser._ 
import io.circe.optics.JsonPath._ 

/** 
    * Created by laurence.geng on 2017/2/2. 
    */ 
object CirceTest extends App { 

    val json: Json = parse(
    """ 
    [ 
    { 
    "metric":"my-metric", 
    "dps":{"1484214238":5,"1484214239":1,"1484214240":4,"1484214241":11} 
    } 
    ] 
    """).getOrElse(Json.Null) 

    val doubleValue: Json => Json = root.each.dps.each.int.modify(_ * 2) 

    println(doubleValue(json).toString()) 

} 

Выход:

[ 
    { 
    "metric" : "my-metric", 
    "dps" : { 
     "1484214238" : 10, 
     "1484214239" : 2, 
     "1484214240" : 8, 
     "1484214241" : 22 
    } 
    } 
] 

Но, actully, что мне нужно сделать, это изменить int значение определенного строкового значения, то есть 1 -> «A», 2 -> «B» и т. д., проблема заключается в следующем: метод «изменить» принимает только функцию, возвращающую тот же тип к входному значению, Я НЕ МОЖЕТ кодировать следующее:

val intToString: Json => Json = root.each.dps.each.int.modify(_.toString) 

и m y ожидаемый результат может выглядеть следующим образом:

[ 
    { 
    "metric" : "my-metric", 
    "dps" : { 
     "1484214238" : "10", 
     "1484214239" : "2", 
     "1484214240" : "8", 
     "1484214241" : "22" 
    } 
    } 
] 

Может ли кто-нибудь дать мне рабочее место (основанное на Цирке)?

+0

Все, что говорит против разбора его собственных структур данных Scala, работать с ними, а затем сериализации их снова? – Reactormonk

+0

Учитывая производительность, я не хочу сериализовать и затем десериализовать. Я хочу преобразовать строку json string в класс case. –

+0

Ты все равно десериализуешь. Вы просто добавили дополнительный шаг декодирования. Сколько данных вы хотите обработать? – Reactormonk

ответ

3

Вы можете сделать это с помощью курсоров circe, но я думаю, что его проще просто преобразовать в класс case и работать над этим.

val json = 
    """ 
    |{ 
    | "metric":"my-metric", 
    | "dps":{"1484214238":5,"1484214239":1,"1484214240":4,"1484214241":11} 
    | } 
    """.stripMargin 

val doc = parse(json).getOrElse(Json.Null) 
val cursor = doc.hcursor 
val dps = cursor.downField("dps") 
val result = dps.withFocus { json: Json => 
    json.mapObject { jsonObject => 
    JsonObject.fromMap(jsonObject.toMap.mapValues { x => 
     Json.fromString(x.asNumber.get.toString) 
    }) 
    } 
} 
+0

Это не лучший способ сделать это, но у меня это было на основе кода, который я лежал вокруг. –

+0

Спасибо за ваш ответ. это может быть не самый лучший способ, но это полезно для меня ~ –

1

Наивное решение:

val doubleValue: Json => Json = root.each.dps.each.json.modify(x => 
    Json.fromString(
    (x.asNumber.getOrElse(throw new Exception("ups")).truncateToInt * 2).toString 
) 
) 
Смежные вопросы