在PowerShell中将JSON转换为CSV

3
这是我的CSV文件:
"name,data
Play,http://{gho}.domain.com/
BDomain,domain.com
Charts,2
Compress,0
CompressJ,0" | ConvertFrom-Csv | ConvertTo-Json

给我:

[
{
    "name":  "Play",
    "data":  "http://{gho}.domain.com/"
},
{
    "name":  "BDomain",
    "data":  "domain.com"
},
{
    "name":  "Charts",
    "data":  "2"
},
{
    "name":  "Compress",
    "data":  "0"
},
{
    "name":  "CompressJ",
    "data":  "0"
}
]

我现在想从我的json文件中获取csv文件,但| ConvertFrom-Json | ConvertTo-CSV的链路无法正常工作,我很好奇为什么?


这是一个重复的内容,请参考:https://dev59.com/S1cP5IYBdhLWcg3w8ea5 - tawfikboujeh
那个文件不存在,所以我不确定它的格式,但是我会去查看一下,谢谢。 - Papi Abi
好的,当尝试获取“results”属性时,PowerShell会抛出无法找到结果的异常。如果只使用标准的|convertfrom-json | convertto-csv,它会返回一些以CSV格式化的元数据。 - Papi Abi
@tawfikboujeh,这里的问题是ConvertFrom-Json的预v7非枚举行为,而解决链接问题的方案中恰好被绕过,在其中访问属性会隐式导致枚举。 - mklement0
2个回答

3
ConvertFrom-Json的输出是单个数组,按照这种方式通过管道传递下来。这是由于ConvertFrom-Json输出的方式所致。它可能会收集所有内容,并在一个Write-Output命令(隐式或显式)中将数组输出,而不是在创建每个对象时将它们流式传输到管道中。这可能是该cmdlet编写方式的后果,也许是必要的。
您当前的代码可能会生成类似于以下的csv:
"Count","Length","LongLength","Rank","SyncRoot","IsReadOnly","IsFixedSize","IsSynchronized"
"5","5","5","1","System.Object[]","False","True","False"

这些是数组的属性,而不是其中的对象。解决方法之一是将数据存储在变量中:

$Json = "name,data
Play,http://{gho}.domain.com/
BDomain,domain.com
Charts,2
Compress,0
CompressJ,0" | 
ConvertFrom-Csv | 
ConvertTo-Json

# Now you can convert back to csv without issue:
$Json = $Json | ConvertFrom-Json
$Json | ConvertTo-Csv -NoTypeInformation

注意:如果直接发送$Json,例如$Json | ConvertFrom-Json | ConvertTo-Csv...,你可能会遇到相同的问题。

对Json对象进行迭代似乎也可以解决这个问题:

$Json = "name,data
Play,http://{gho}.domain.com/
BDomain,domain.com
Charts,2
Compress,0
CompressJ,0" | 
ConvertFrom-Csv | 
ConvertTo-Json

$Json | 
ConvertFrom-Json |
ForEach-Object{ $_ } | 
ConvertTo-Csv -NoTypeInformation

感谢@notjustme,你可以使用(...)来缩短它,例如:
($json | ConvertFrom-Json) | ConvertTo-Csv

注意:根据mklement0的回答进行更正。

所有这些选项本质上都是将数组放在管道前面,以绕过ConvertFrom-Json的内部行为。

再次强调,我不确定ConvertFrom-Json为什么会出现这种行为。如果我找到更正式的解释,我将更新此内容。


1
$($json | ConvertFrom-Json) | ConvertTo-Csv 应该可以正常工作。 - notjustme
@notjustme 我没有想到,但是是的,它应该可以工作。 - Steven
+1;re _why_:请看我的回答。至于 $(...)(...) 就可以了,而且通常更可取 - 参见这个答案 - mklement0
感谢一如既往的支持。遗憾的是我在这种情况下没有检查7+。我同意我很少在扩展字符串之外使用$(...)。当时我在复制@notjustme的评论,所以错过了它。 - Steven
哦,肌肉记忆...每天都要扩展这么多字符串。 :) - notjustme

1

为了补充Steven的有用回答,并提供简明扼要的总结和跨版本的视角:

PowerShell [Core] v7+ 中,不需要额外的努力:将| ConvertFrom-Json | ConvertTo-Csv添加到您的代码中即可正常工作。
Windows PowerShell 和 PowerShell [Core] v6.x 中,您需要强制枚举 ConvertFrom-Json 的输出,以便ConvertTo-Csv 正确工作,因为与 PowerShell 通常的行为相反,ConvertFrom-Json 将 JSON 数组作为一个整体,作为单个对象输出到管道中。
使用(...),即分组运算符是强制枚举的最简单方法 - 即将整个数组/集合的元素逐个发送到管道中。这种行为不寻常,促使了 v7+ 更改 - 有关详细信息,请参见 this answer
# Works in all PowerShell versions, but in v7+ the (...) is no longer necessary.
(
"name,data
Play,http://{gho}.domain.com/
BDomain,domain.com
Charts,2
Compress,0
CompressJ,0" | ConvertFrom-Csv | ConvertTo-Json |
  ConvertFrom-Json
) | ConvertTo-Csv -NoTypeInformation

This yields:

"name","data"
"Play","http://{gho}.domain.com/"
"BDomain","domain.com"
"Charts","2"
"Compress","0"
"CompressJ","0"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接