Convierta a csv desde json en powershell

Sep 23 2020

este es mi csv:

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

Me da:

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

Ahora me gustaría recuperar ese csv de mi json, sin embargo, las cadenas de | ConvertFrom-Json | ConvertTo-CSV no funciona, y tengo curiosidad ¿por qué no?

Respuestas

1 mklement0 Sep 25 2020 at 05:11

Para complementar la útil respuesta de Steven con un breve resumen y una perspectiva de edición cruzada:

  • En PowerShell [Core] v7 + , no se necesita ningún esfuerzo adicional: agregar | ConvertFrom-Json | ConvertTo-Csva su código funciona tal cual.

  • En Windows PowerShell y PowerShell [Core] v6.x , es necesario forzar la enumeración de ConvertFrom-Jsonla salida para ConvertTo-Csvque funcione correctamente, ya que, en contra del comportamiento habitual de PowerShell, ConvertFrom-Jsongenera una matriz JSON como un todo, como un solo objeto para la canalización .

    • Es el hecho de que este comportamiento es inusual lo que provocó el cambio v7 +; consulte esta respuesta para obtener información general.

    • La forma más sencilla de forzar la enumeración, es decir, enviar los elementos de una matriz / colección de salida como un todo uno por uno a la tubería es utilizar (...)el operador de agrupación .

# 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

Esto produce:

"name","data"
"Play","http://{gho}.domain.com/"
"BDomain","domain.com"
"Charts","2"
"Compress","0"
"CompressJ","0"
2 Steven Sep 22 2020 at 23:59

La salida de ConvertFrom-Jsonuna matriz única se transmite por la tubería como tal. Esta es una consecuencia de cómo ConvertFrom-Jsonse escribe su salida. Probablemente esté recopilando todo y generando la matriz en un Write-Outputcomando (implícito o no) en lugar de transmitir cada objeto por la tubería a medida que se crean. Probablemente sea una consecuencia de cómo está escrito el cmdlet y puede haber sido necesario.

Es probable que su código actual genere un csv como:

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

Estas son las propiedades de la matriz, no los objetos que contiene. Una forma de evitarlo es simplemente estacionar los datos en una 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

Nota: si envía $ Json directamente, $Json | ConvertFrom-Json | ConvertTo-Csv...es posible que tenga el mismo problema.

Iterar sobre los objetos Json también parece funcionar:

$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

Gracias a @notjustme, puedes acortar esto usando (...)like:

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

Nota: Corregido por la respuesta de mklement0 .

Todas estas opciones esencialmente colocan la matriz frente a la tubería para evitar el comportamiento interno de ConvertFrom-Json

Nuevamente, no estoy 100% seguro de por qué ConvertFrom-Json se comporta de esta manera. Actualizaré con información adicional cuando encuentre una explicación más formal.