0

Please help me to convert my below json file to csv.

{
    "count":  12,
    "name":  "Daily Ticket",
    "columnNames":  [
                        "User",
                        "Channel",
                        "Date",
                        "# of Closed Incidents",
                        "Open",
                        "Response",
                        "Remark",
                        "Closed"
                    ],
    "rows":  [
                    [
                     "abc",
                     "Service Web",
                     "\u00272020-06-13 00:00:00\u0027",
                     "1",
                     "0",
                     "0",
                     "0",
                     "1"
                 ],
                 [
                     "xyz",
                     "Email",
                     "\u00272020-06-13 00:00:00\u0027",
                     "21",
                     "1",
                     "0",
                     "10",
                     "7"
                 ]
             ]
}

I want column names as header and rows as rows separated with comma in csv.

The expected output is like below:

User,Channel,Date,# of Closed Incidents,Open,Response,Remark,Closed
abc,Service Web,\u00272020-06-13 00:00:00\u0027,1,0,0,0,1
xyz,Email,\u00272020-06-13 00:00:00\u0027,1,0,0,0,1
1
  • 1
    Instead of ConvertTo-JSON, use ConvertTo-CSV and you get CSV report directly. Commented Jun 14, 2020 at 14:32

3 Answers 3

1

I'd offer the simplest approach I know:

$jsonText = @'
{"count":12,"name":"Daily Ticket","columnNames":["User","Channel","Date","# of Closed Incidents","Open","Response","Remark","Closed"],"rows":[["abc","Service Web","\u00272020-06-13 00:00:00\u0027","1","0","0","0","1"],["xyz","Email","\u00272020-06-13 00:00:00\u0027","21","1","0","10","7"]]}
'@
$json = $jsonText | ConvertFrom-Json

$jsonCsvLines = [System.Collections.ArrayList]::new()
[void]$jsonCsvLines.Add( $json.columnNames -join ',')
foreach ( $jsonCsvRow in $json.rows ) {
    [void]$jsonCsvLines.Add( $jsonCsvRow -join ',')
}

$jsonCsvLines

$jsonCsv = $jsonCsvLines |
    ConvertFrom-Csv -Delimiter ',' |
    ConvertTo-Csv -Delimiter ',' -NoTypeInformation

$jsonCsvNoQuotes = $jsonCsv -replace [regex]::Escape('"')

Here

  • the here-string $jsonText is a compressed version of your example;
  • the $jsonCsvLines is simple collection (no CSV);
  • the $jsonCsv is a genuine csv where all fields are enclosed in double quotes, while the $jsonCsvNoQuotes is a csv where no field is enclosed in double quotes.
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for the solution. Coming back again to this thread, how can I select only few columns from the same json and add it to csv? For e.g., I need user,channel,response in the csv and not the other columns. How can I achieve this?
Please ask another question instead. Don't forget to include a minimal reproducible example.
0

So far as I can tell (and I'm happy to be corrected) the format of the resulting PSCustomObjects from ConvertTo-JSON isn't suitable for direct consumption by ConvertTo-CSV

You need to relate the elements in row array with the column names. Create an array of objects with the correct property names and values. The way I solved this was to use the array index to associate each row array element with a column name:

$JSON = Get-Content 'C:\Temp\sample.json' | ConvertFrom-Json 

    $Rows = 
    ForEach($Row in $JSON.Rows )
    {
        $TmpHash = [Ordered]@{}
        For($i = 0; $i -lt $Row.Length; ++$i )
        {
            $TmpHash.Add( $JSON.columnNames[$i], $Row[$i] )
        }
        [PSCustomObject]$TmpHash
    }

    $Rows | ConvertTo-Csv -NoTypeInformation

Obviously change the file name or whatnot.

On my workstation this results are like:

"User","Channel","Date","# of Closed Incidents","Open","Response","Remark","Closed"
"abc","Service Web","'2020-06-13 00:00:00'","1","0","0","0","1"
"xyz","Email","'2020-06-13 00:00:00'","21","1","0","10","7"

There are definitely different code patterns that can be employed here, but the theme should work.

One important difference is you had a unicode character for apostrophe \u0027 in the source JSON in my output that's properly interpreted. Just pointing out because it's one thing that differs from your sample.

I think this is pretty close to what you needed. Let me know if anything. Thanks.

1 Comment

Thank you for the solution. Coming back again to this thread, how can I select only few columns from the same json and add it to csv? For e.g., I need user,channel,response in the csv and not the other columns. How can I achieve this?
0

Sorry to keep this going, but I'm intrigued by JosefZ's answer . This is not to override or critique, it's just for conversation's sake.

Considering ConvertFrom-Json returns PSCustomObjects my first answer went directly to using the same as input for ConvertTo-Csv. Even though creating Csv strings is common in the field it didn't occur to me at the time. I also didn't notice your sample output was unquoted, apologies for that.

At any rate here's my interpretation of JosefZ's answer

Note: In any of these samples -join would work just as well. I just invoking static methods; however I don't know advantages / disadvantages between -join & [String]::Join().

$JSON = Get-Content 'C:\Temp\sample.json' | ConvertFrom-Json 

$Lines = .{
    [String]::Join( ',', $JSON.columnNames )
    $JSON.rows | ForEach-Object{ [String]::Join( ',', $_ ) }        
}

# $Lines is already in unquoted CSV format.  If you want to quote it
$Lines | ConvertFrom-Csv | ConvertTo-Csv -NoTypeInformation

If you only need the quoted or unquoted you can drop the $Lines assignment and pipe all the way through.

Quoted:

$JSON = Get-Content 'C:\Temp\sample.json' | ConvertFrom-Json 

.{
    [String]::Join( ',', $JSON.columnNames )
    $JSON.rows | ForEach-Object{ [String]::Join( ',', $_ ) }
} | ConvertFrom-Csv | ConvertTo-Csv -NoTypeInformation

Un-Quoted:

$JSON = Get-Content 'C:\Temp\sample.json' | ConvertFrom-Json 

.{
    [String]::Join( ',', $JSON.columnNames )
    $JSON.rows | ForEach-Object{ [String]::Join( ',', $_ ) }
} 

This approach is a more concise as it can be slimmed to only a few lines. Concise doesn't always mean better or more readable, so again this isn't to override any other approach.

Of course, I don't know what you intend to do with the data after it's properly formatted. If you need to write to a file a simple | Out-File... can be added to the end of any of the above.

1 Comment

Thank you for the solution. Coming back again to this thread, how can I select only few columns from the same json and add it to csv? For e.g., I need user,channel,response in the csv and not the other columns. How can I achieve this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.