使用Dataweave 2.0将JSON对象展开为嵌套JSON对象

问题描述

我有这个展平的对象

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

我想编写一个数据编织将其转换为原始对象,即

{
  "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文章尝试以下数据编织表达式: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,index) -> propToJSON((key),value))
))

输出:

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

另一种方法是使用4.3中引入的 update 运算符。使用此运算符,我们可以进行upsert(不存在时插入值,如果存在则进行更新)。使用该操作和reduce可以从表达式的每个部分开始进行正确的更新

%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,index) -> {key: key,value: value})
    reduce ((item,resultObject = {} ) -> do {
        upsert(resultObject,(item.key as String splitBy '.'),item.value)
    })
,

这类似于@olamiral解决方案,但经过简化并支持数组。

x   <- floor(runif(50,40))

具有此有效载荷:

g1 <- (x >= 0) & (x<= 10)
g2 <- (x >= 11) & (x<= 20)
g3 <- (x >= 21) & (x<= 30)
g4 <- (x>= 31)

正在产生以下输出:

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

此解决方案不支持在同一数组中混合简单值和对象。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...