2017-05-18 23 views
6

我有一些json,其中包含一些字段被平化爲bson-ish格式,如{"foo.bar" : "bash"}。我想將其轉換爲以下表示{"foo" : { "bar" : "bash"}},並想知道我會在哪裏做這樣的操作。使問題複雜化是可能有多個這樣的字段需要適當地合併,例如, {"foo.bar" : "a", "foo.bash" : "b", "foo.baz" : "c"} - >{"foo" : { "bar" : "a", "bash" : "b", "baz" : "c"}}使用循環預處理點符號樣式字段

回答

7

這裏有一個快速的實現:

import io.circe.Json 

val Dotted = "([^\\.]*)\\.(.*)".r 

def expandDotted(j: Json): Json = j.arrayOrObject(
    j, 
    js => Json.fromValues(js.map(expandDotted)), 
    _.toList.map { 
    case (Dotted(k, rest), v) => Json.obj(k -> expandDotted(Json.obj(rest -> v))) 
    case (k, v) => Json.obj(k -> expandDotted(v)) 
    }.reduceOption(_.deepMerge(_)).getOrElse(Json.obj()) 
) 

我還沒有真正使用或詳細測試,但它似乎工作:

scala> import io.circe.literal._ 
import io.circe.literal._ 

scala> val j1 = json"""{"foo.bar" : "a", "foo.bash" : "b", "foo.baz" : "c"}""" 
j1: io.circe.Json = 
{ 
    "foo.bar" : "a", 
    "foo.bash" : "b", 
    "foo.baz" : "c" 
} 

scala> expandDotted(j1) 
res1: io.circe.Json = 
{ 
    "foo" : { 
    "baz" : "c", 
    "bash" : "b", 
    "bar" : "a" 
    } 
} 

而且具有較深的嵌套:

scala> expandDotted(json"""{ "x.y.z": true, "a.b": { "c": 1 } }""") 
res2: io.circe.Json = 
{ 
    "a" : { 
    "b" : { 
     "c" : 1 
    } 
    }, 
    "x" : { 
    "y" : { 
     "z" : true 
    } 
    } 
} 

只是爲了確認它不會出現亂碼:

scala> expandDotted(json"""{ "a.b": true, "x": 1 }""").noSpaces 
res3: String = {"x":1,"a":{"b":true}} 

注意,在(即導致既JSON對象和非對象JSON值,或者多個非對象值路徑)「衝突」的情況下,該行爲是的Json#deepMerge

scala> expandDotted(json"""{ "a.b": true, "a": 1 }""").noSpaces 
res4: String = {"a":1} 

scala> expandDotted(json"""{ "a": 1, "a.b": true }""").noSpaces 
res5: String = {"a":{"b":true}} 

......這可能是你想要的,但在這種情況下你也可能會失敗,或者不會擴大碰撞路徑,或者做任何你能想到的其他事情。