当输入在第一条记录中没有全部 headers 时,如何使用 DataWeave 创建带有 headers 的 CSV 输出
How to use DataWeave to create a CSV output with headers when the input doesn't has all headers in the first record
我有json个没有固定长度的数组,例如
[
{
a: 1
},
{
a: 1,
b: 2
},
{
a: 1,
c: 3
},
{
a: 1,
b: 2,
d: 4,
f: 6
}
]
我需要使用 header 将它们转换为 CSV 文件。下面的脚本只有 return header 的第一行,而不是所有列。可以知道怎么操作吗?
%dw 2.0
output application/csv separator = " ", escape = "", header = true, encoding="UTF-8"
---
payload
我期待这样的结果
我对问题的理解是,您的输入没有包含输出 CSV 的所有 header 的第一行行。需要从每一行中收集 header。
我通过从每条记录中获取所有 header 来分别计算所有 header 解决了这个问题,然后在开始时手动创建一行 headers 元素, 并禁用自动 header 生成。我不对性能提出任何要求。这对于更大的有效负载可能是不利的,因为该脚本基本上对每条记录进行两次迭代。我将逻辑封装在函数中以便于重用。
主要的复杂性在于重新创建输出记录,为缺失的列添加空值并遵守函数 addMissingValue() 中的原始顺序。这是必需的,因为这种情况不在 DataWeave built-in 对 CSV 的支持范围内。
%dw 2.0
output application/csv header=false
var collectHeaders=payload
map namesOf($) reduce ((item, accumulator=[]) -> (accumulator ++ item) distinctBy ((item, index) -> item) )
fun createHeaderLine(x)=[collectHeaders map {($): $}
reduce ((item, accumulator={}) -> accumulator ++ item)]
fun addMissingValue(o)=
collectHeaders
map ( if (o[$]== null) {($): null} else {($): o[$]} )
reduce ((item, accumulator={}) -> accumulator ++ item)
---
createHeaderLine(payload) ++ (payload map addMissingValue($))
输入(为清楚起见,格式正确 JSON,如果你的格式是 Java 或其他格式,它的工作方式相同):
[
{
"a": 1
},
{
"a": 1,
"b": 2
},
{
"a": 1,
"c": 3
},
{
"a": 1,
"b": 2,
"d": 4,
"f": 6
}
]
输出:
a,b,c,d,f
1,,,,
1,2,,,
1,,3,,
1,2,,4,6
我注意到您的示例脚本使用了由多个空格组成的分隔符。我没有在我的解决方案中使用它,因为它不相关。如果需要,请随时添加。请注意,CSV 是一种带分隔符的文本格式,而不是固定长度格式。
另一个解决方案是使用我的 csv-module (https://github.com/rbutenuth/csv-module)。您在配置中指定 headers 并且不要从输入数据中获取它们。
即使您输入的数据在整个数据集中缺少一列,也能正常工作。并提供元数据以便更轻松地使用 DataWeave 进行映射。
我有json个没有固定长度的数组,例如
[
{
a: 1
},
{
a: 1,
b: 2
},
{
a: 1,
c: 3
},
{
a: 1,
b: 2,
d: 4,
f: 6
}
]
我需要使用 header 将它们转换为 CSV 文件。下面的脚本只有 return header 的第一行,而不是所有列。可以知道怎么操作吗?
%dw 2.0
output application/csv separator = " ", escape = "", header = true, encoding="UTF-8"
---
payload
我期待这样的结果
我对问题的理解是,您的输入没有包含输出 CSV 的所有 header 的第一行行。需要从每一行中收集 header。
我通过从每条记录中获取所有 header 来分别计算所有 header 解决了这个问题,然后在开始时手动创建一行 headers 元素, 并禁用自动 header 生成。我不对性能提出任何要求。这对于更大的有效负载可能是不利的,因为该脚本基本上对每条记录进行两次迭代。我将逻辑封装在函数中以便于重用。
主要的复杂性在于重新创建输出记录,为缺失的列添加空值并遵守函数 addMissingValue() 中的原始顺序。这是必需的,因为这种情况不在 DataWeave built-in 对 CSV 的支持范围内。
%dw 2.0
output application/csv header=false
var collectHeaders=payload
map namesOf($) reduce ((item, accumulator=[]) -> (accumulator ++ item) distinctBy ((item, index) -> item) )
fun createHeaderLine(x)=[collectHeaders map {($): $}
reduce ((item, accumulator={}) -> accumulator ++ item)]
fun addMissingValue(o)=
collectHeaders
map ( if (o[$]== null) {($): null} else {($): o[$]} )
reduce ((item, accumulator={}) -> accumulator ++ item)
---
createHeaderLine(payload) ++ (payload map addMissingValue($))
输入(为清楚起见,格式正确 JSON,如果你的格式是 Java 或其他格式,它的工作方式相同):
[
{
"a": 1
},
{
"a": 1,
"b": 2
},
{
"a": 1,
"c": 3
},
{
"a": 1,
"b": 2,
"d": 4,
"f": 6
}
]
输出:
a,b,c,d,f
1,,,,
1,2,,,
1,,3,,
1,2,,4,6
我注意到您的示例脚本使用了由多个空格组成的分隔符。我没有在我的解决方案中使用它,因为它不相关。如果需要,请随时添加。请注意,CSV 是一种带分隔符的文本格式,而不是固定长度格式。
另一个解决方案是使用我的 csv-module (https://github.com/rbutenuth/csv-module)。您在配置中指定 headers 并且不要从输入数据中获取它们。
即使您输入的数据在整个数据集中缺少一列,也能正常工作。并提供元数据以便更轻松地使用 DataWeave 进行映射。