簡體   English   中英

使用 Dataweave 2.0 將 JSON 對象展開為嵌套的 JSON 對象

[英]Unflatten a JSON Object into nested JSON Object using Dataweave 2.0

我有這個扁平化的對象

{
  "abc.def.ghi": "foo",
  "abc.def.jkl": "bar"
}

我想寫一個dataweave把它轉換成原始對象,即

{
  "abc": {
    "def": {
      "ghi": "foo",
      "jkl": "bar"
    }
  }
}

我試圖避免對密鑰進行硬編碼,因為它是一個相當大的對象,所以我不想要這樣的東西:

%dw 2.0
var test = {
    "abc.def.ghi": "foo",
    "abc.def.jkl": "bar"
}
output application/json
---
{
    abc: {
        def: {
            ghi: test."abc.def.ghi",
            jkl: test."abc.def.jkl"
        }
    }
}

我可以使用一些可用的 dataweave 函數組合來實現這一點嗎?

這是我迄今為止嘗試過的:

%dw 2.0
var test = {
    "abc.def.ghi": "foo",
    "abc.def.jkl": "bar"
}
output application/json
---
test mapObject ((value, key) -> 
    (key as String splitBy  ".")[-1 to 0]  
         reduce ((item, acc = value) -> 
             (item): acc     
/*
   First item=ghi,acc=foo => acc = {ghi: "foo"} 
   next item=def, acc={ghi: "foo"} => acc={def:{ghi:"foo"}}
*/
    )
)

但這會生成某種單獨的嵌套 JSON 對。 下面是上面代碼的輸出:

{
  "abc": {
    "def": {
      "ghi": "foo"
    }
  },
  "abc": {
    "def": {
      "jkl": "bar"
    }
  }
}

您可以根據 Mohammad Mazhar Ansari 撰寫的這篇 Apisero 文章嘗試以下 dataweave 表達式: https ://apisero.com/property-to-yaml-file-conversion-using-mulesoft/

%dw 2.0
var test = {
    "abc.def.ghi": "foo",
    "abc.def.jkl": "bar"
}
import * from dw::core::Strings
output application/json
fun generateArray (obj) = obj pluck (v, k) -> (k): v
fun isSubChildExists (key) = (((key) splitBy ("."))[1] != null)
fun propToJSON(key, value) = if (isSubChildExists(key)) {
   (substringBefore(key, ".")) : propToJSON(substringAfter(key, "."), value)
}
else
   (key): value
fun arrToObj(arr) = arr reduce ((env, obj={}) -> obj ++ env)
fun CombineObjBasedOnKey (Obj) =
if (typeOf(Obj) == Array and sizeOf(Obj..) > 1)
((Obj groupBy (item, index) -> keysOf(item)[0]) mapObject ((value, key, index) ->
   (if (typeOf(value) == Array)
       (key): CombineObjBasedOnKey(value..'$key')
   else if (typeOf(value) == String)
       value
   else
       (key): value
) as Object))
else
   Obj[0]
---
CombineObjBasedOnKey(generateArray(test) map ((item, index) -> item mapObject ((value, key, index) -> propToJSON((key), value))
))

輸出:

{
  "abc": {
    "def": {
      "ghi": "foo",
      "jkl": "bar"
    }
  }
}

另一種方法是使用 4.3 中引入的更新運算符。 使用這個操作符,我們可以執行 upsert(在不存在時插入值或如果存在則更新)使用它和減少我們可以從表達式的每個部分開始並進行適當的更新

%dw 2.0
output application/json
import * from dw::util::Values


fun upsert(object: {}, path:Array<String>, value: Any): Object = do {
    path match {
        case [] -> object
        case [x ~ xs] -> 
                if(isEmpty(xs))
                    object update  {
                        case ."$(x)"! -> value                                
                    }
                else
                    object update  {
                        case selected at ."$(x)"! -> 
                            //selected is going to be null when the value is not present  
                            upsert(selected default {}, xs, value)
                    }  
    }
}
---
payload 
    pluck ((value, key, index) -> {key: key, value: value})
    reduce ((item, resultObject = {} ) -> do {
        upsert(resultObject, (item.key as String splitBy '.') , item.value)
    })

這類似於@olamiral 解決方案,但簡化並支持數組。

%dw 2.0
output application/json

// Creates a array of key-value tuples with the object structure. 
// I was not able to use entriesOf() because I had to modify the key to split it
var tuples = payload pluck ((value, key, index) -> 
    { 
        k: key splitBy("."), 
        v: value}
    )

// Using groupBy, group the childs and maps to an object structure.
fun flatToObject(tuples, index) =
    (tuples groupBy $.k[index]) mapObject ((groupedTuples, key, idx) -> 
        if(groupedTuples[0].k[index + 1]?) 
            // Has more levels
            { (key): flatToObject(groupedTuples,index + 1) }
        else 
            // It's a leaf
            { (key): if (sizeOf(groupedTuples.v) > 1)
                    // It has an array of values
                    groupedTuples.v 
                else 
                    // It has a single value
                    groupedTuples.v[0]
            }
    )
---
flatToObject(tuples,0)

使用此有效載荷:

{
    "abc.def.ghi": "foo",
    "abc.def.jkl": "bar",
    "abc.de.f": "bar2",
    "abc.def.jkm": "bar3",
    "abc.de.f": 45
}

它產生這個輸出:

{
  "abc": {
    "def": {
      "ghi": "foo",
      "jkl": "bar",
      "jkm": "bar3"
    },
    "de": { 
      "f": ["bar2", 45]
    }
  }
}

此解決方案不支持在同一數組中混合簡單值和對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM