Convert to csv from json in powershell

我是研究僧i 提交于 2021-01-28 12:00:57

问题


this is my csv:

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

Gives me:

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

I would now like to get that csv back from my json, however the chains of | ConvertFrom-Json | ConvertTo-CSV are not working, and I am curious why not?


回答1:


To complement Steven's helpful answer with a succinct summary and a cross-edition perspective:

  • In PowerShell [Core] v7+, no extra effort is needed: appending | ConvertFrom-Json | ConvertTo-Csv to your code works as-is.

  • In Windows PowerShell and PowerShell [Core] v6.x, you need to force enumeration of ConvertFrom-Json's output in order for ConvertTo-Csv to work correctly, because, against PowerShell's usual behavior, ConvertFrom-Json outputs a JSON array as a whole, as a single object to the pipeline.

    • It is the fact that this behavior is unusual that prompted the v7+ change - see this answer for background information.

    • The simplest way to force enumeration - i.e. to send an output-as-a-whole array's / collection's elements one by one to the pipeline is to use (...), the grouping operator.

# 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"



回答2:


The output of ConvertFrom-Json is single array being passed down the pipeline as such. This is a consequence of how ConvertFrom-Json is writing it's output. It's probably collecting everything and outputting the array in one Write-Output command (implicit or otherwise) instead of streaming each object down the pipeline as they are created. It's probably a consequence of how the cmdlet is written and may have been necessary.

Your current code is likely generating a csv like:

"Count","Length","LongLength","Rank","SyncRoot","IsReadOnly","IsFixedSize","IsSynchronized"
"5","5","5","1","System.Object[]","False","True","False"

These are the properties of the array not the objects in it. One way to get around it just park the data in a variable:

$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

Note: if you send $Json directly like $Json | ConvertFrom-Json | ConvertTo-Csv... you may have the same issue.

Iterating over the Json objects also seems to work:

$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

Thanks to @notjustme , you can shorten this using (...) like:

($json | ConvertFrom-Json) | ConvertTo-Csv

Note: Corrected per mklement0's answer.

All of these options are essentially placing the array in-front of the pipe to bypass the internal behavior of ConvertFrom-Json

Again not 100% sure why ConvertFrom-Json behaves this way. I'll update with additional information when I find a more formal explanation.



来源:https://stackoverflow.com/questions/64014087/convert-to-csv-from-json-in-powershell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!