I have a CSV, let's call it test.csv
"country","city","population","remarks"
"germany","munih","1472000","i am a
line
brake"
"italy","rome","2873000","<>|'"
"spain","madrid","6642000","!"§$%&/("
I need a full HTML escaped 2D JS-array without headers and names as like below:
"germany","munih","1472000","i am a \nline\nbrake"
respectively:
var MyVar = [["germany","munih","1472000","i am a \nline\nbrake"],["italy","rome","2873000","<>|'"],["spain","madrid","6642000","!§$%&/(""]];
ConvertTo-Json can escape, but did not find any easy way to produce an 2D-Array without Object Names:
Import-Csv ".\test.csv" | ConvertTo-Json -EscapeHandling EscapeHtml
[
{
"country": "germany",
"city": "munih",
"population": "1472000",
"remarks": "i am a \r\nline\r\nbrake"
},
{
"country": "italy",
"city": "rome",
"population": "2873000",
"remarks": "\u003c\u003e|\u0027"
},
{
"country": "spain",
"city": "madrid",
"population": "6642000",
"remarks": "!§$%\u0026/(\u0022"
}
]
ConverTo-CSV does a good job, but can't escape:
Import-Csv ".\test.csv" | ConvertTo-Csv -UseQuotes Always
"country","city","population","remarks"
"germany","munih","1472000","i am a
line
brake"
"italy","rome","2873000","<>|'"
"spain","madrid","6642000","!§$%&/("""
Following routine works. But I believe, there must be easier way.
$t1 = Import-Csv ".\test.csv"
$arr_len = $t1.Count
$obj_len = $t1[0].Psobject.Properties.value.count
$str_builder = [System.Text.StringBuilder]::new()
for ($i=0; $i -lt $arr_len; $i++){
#first outer loop
if ($i -eq 0){[void]$str_builder.Append('var MyVar = [')}
for ($j=0; $j -lt $obj_len; $j++){
#first inner loop
if ($j -eq 0){[void]$str_builder.Append('[')}
#$t1[$i].Psobject.Properties.Name[$j]
$each = $t1[$i].Psobject.Properties.Value[$j]
$each_esc = ([System.Net.WebUtility]::HtmlEncode($each)) -replace("`r`n|`r|'n","\n")
[void]$str_builder.Append('"')
[void]$str_builder.Append($each_esc)
[void]$str_builder.Append('"')
#last inner loop
if ($j -eq ($obj_len-1)){
if ($i -ne ($arr_len-1)){
[void]$str_builder.Append('],')
} else {
[void]$str_builder.Append(']')
}
} else{
[void]$str_builder.Append(',')
}
}
#last outer loop
if ($i -eq ($arr_len-1)){[void]$str_builder.Append('];')}
}
$final = $str_builder.ToString()
[void]$str_builder.Clear()
Any hints, ideas? Thx :)
You could simplify the code like:
Add-Type -AssemblyName System.Web
$data = Import-Csv -Path 'D:\Test\test.csv'
$jsData = foreach ($item in $data) {
# create an array of quoted encoded strings
$values = $item.PsObject.Properties.Value | ForEach-Object {
'"{0}"' -f [System.Web.HttpUtility]::HtmlEncode(($_ -replace '\r?\n', '\n'))
}
# output the encoded strings grouped inside square brackets
'[{0}]' -f ($values -join ',')
}
# combine the resulting data into a 2D array
$result = 'var MyVar = [{0}];' -f ($jsData -join ',')
$result
Output:
var MyVar = [["germany","munih","1472000","i am a \nline\nbrake"],["italy","rome","2873000","<>|'"],["spain","madrid","6642000","!§$%&/(""]];
Right from the given input it isn't possible to produce the required output.
Youe have to create a nested list first, then the json document.
Try the following:
$list = [System.Collections.Generic.List[psobject]]::new()
foreach($item in $input) {
$nestedList = [System.Collections.Generic.List[string]]::new()
$itemProps = $item.psobject.properties
foreach($itemProp in $itemProps) {
$nestedList.Add($itemProp.Value)
}
$list.Add($nestedList)
}
$list | ConvertTo-Json -EscapeHandling EscapeHtml
<#
$PSVersionTable.PSVersion
Major Minor Patch PreReleaseLabel BuildLabel
----- ----- ----- --------------- ----------
7 1 0
#>
$fieldsCount = 4
$rawText = #'
"country","city","population","remarks"
"germany","munih","1472000","i am a
line
brake"
"italy","rome","2873000","<>|'"
"spain","madrid","6642000","!"§$%&/("
'#
$rawArray = $rawText.Trim("`"") -split "`r`n" -join "," -split '","'
$table = $(for ($i = $fieldsCount; $i -lt $rawArray.Count; $i += $fieldsCount){
[PSCustomObject]#{
country = $rawArray[$i]
city = $rawArray[$i+1]
population = $rawArray[$i+2]
remarks = $rawArray[$i+3]
}
})
$table | ConvertTo-Json
<#
country city population remarks
------- ---- ---------- -------
germany munih 1472000 i am a ,line,brake
italy rome 2873000 <>|'
spain madrid 6642000 !"§$%&/(
[
{
"country": "germany",
"city": "munih",
"population": "1472000",
"remarks": "i am a ,line,brake"
},
{
"country": "italy",
"city": "rome",
"population": "2873000",
"remarks": "<>|'"
},
{
"country": "spain",
"city": "madrid",
"population": "6642000",
"remarks": "!\"§$%&/("
}
]
#>
Related
Currently I am fetching the data from flat CSV and converting it to json. I am able to take it two level down with three Arrays like below
The CSV file contains the following data.
The code I have written to achieve the above is using array,powershell object and convertto-json
$ArrayAPPName = #()
$ArrayAPProles = #()
$Arrayserver= #()
$i = 0
foreach ($item in $CSV) {
if ($i -eq 0) {
$JSONappname = $($item.'AppName')
$JSONapprole = $($item.'ROLE')
}
if ($($item.'AppName') -ne $JSONappname) {
$ArrayAPPName += [pscustomobject]#{
AppName = $JSONappname;
Roles = $ArrayJSONroles
}
}
$ArrayJSONserver = [pscustomobject]#{
CPU = $item.CPU;
RAM = ([int]$item.Memory);
}
if ($($item.'AppName') -eq $JSONappname)
{
[array]$ArrayJSONroles += [pscustomobject]#{
Role = $($item.'ROLE');
Server = $ArrayJSONserver
}
}
else {
[array]$ArrayJSONroles = [pscustomobject]#{
Role = $($item.'ROLE');
Server = $ArrayJSONserver
}
}
$JSONappname = $($item.'AppName')
$i++
}
$ArrayAPPName += [pscustomobject]#{
Name = $JSONappname;
Roles= $ArrayJSONroles
}
$ArrayAPPName = [pscustomobject]#{
Apps = $ArrayAPPName | Select-Object -Property Name, Roles
}
$ArrayAPPName = $ArrayAPPName | ConvertTo-Json -Depth 10
However, Now we have situation where for same role we can have multiple
server request. so for each application name, we can have multiple application
role and for each application role we can have multiple Server.
{
"Apps": [
{
"AppName": "ABC",
"Roles": [
{
"Role": "App",
"Server": [
{
"CPU": "2",
"Memory": "1024",
},
{
"CPU": "2",
"Memory": "2084",
}
]
}
]
}
]
}
I have a JSON file with below format:
[
{
"id": "12345",
"name": "test_group",
"members":
[
{
"id": "11111",
"name": "test_member_1"
},
{
"id": "22222",
"name": "test_member_2"
},
{
"id": "33333",
"name": "test_member_3"
}
]
}
]
My requirement is to convert these into below format/output to CSV:
groupId,groupName,memberId,memberName
12345,test_group,11111,test_member_1
12345,test_group,22222,test_member_2
12345,test_group,33333,test_member_3
I am able to get the array index values as concatenated strings in one column using below code, but need the output in above format only:
$jsonfile = 'C:\newjsonfile.json'
$outputcsv = 'C:\newcsvfile.csv'
$fields=#(
#{Name='groupId';Expression={$_.id}}
,#{Name='groupName';Expression={$_.name}}
,#{Name='memberId';Expression={$_.members.id, -join '|~|'}}
,#{Name='memberName';Expression={$_.members.name -join '|~|'}}
)
(Get-Content $jsonfile -Raw | ConvertFrom-Json) |
Select-Object -Property $fields |
Export-Csv $outputcsv -NoTypeInformation -Force
CSV Output from above query:
groupId, groupName, memberId, memberName
----- --------- -------- ----------
12345, test_group, {11111 |~| 22222 |~| 33333}, {test_member_1 |~| test_member_2 |~| test_member_3}
Please help/suggest in resolving this query in PowerShell.
Current version is:
PS C:\WINDOWS\system32> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 17134 407
You want to combine information from a parent object with information from nested child objects. To do that you need to store the information from the parent in variables and then inject it when processing the child objects:
(Get-Content $jsonfile -Raw | ConvertFrom-Json) | ForEach-Object {
$gid = $_.id
$name = $_.name
$_.members |
Select-Object #{n='groupId';e={$gid}},
#{n='groupName';e={$name}},
#{n='memberId';e={$_.id}},
#{n='memberName';e={$_.name}}
} | Export-Csv $outputcsv -NoType -Force
I need to get the index number for an item in array using the items value. I can't seem to see in the documentation how to achieve this.
$json = New-Object Chilkat.JsonObject
$jsonStr = "{ `"id`": 1, `"name`": `"A green door`", `"tags`": [`"home`", 22, `"green`"], `"price`": 125 }"
$success = $json.Load($jsonStr)
if ($success -ne $true) {
$($json.LastErrorText)
exit
}
# Get the "tags" array, which contains "home", 22, "green"
$tagsArray = $json.ArrayOf("tags")
if ($tagsArray -eq $null ) {
$("tags member not found.")
exit
}
Use the JSON code generator at http://tools.chilkat.io/jsonParse.cshtml
For example, if you past the following into the online tool:
{ "id": 1, "name": "A green door", "tags": ["home", 22, "green"], "price": 125 }
You'll get
$json = New-Object Chilkat.JsonObject
# Insert code here to load the above JSON into the json object.
$id = $json.IntOf("id")
$name = $json.StringOf("name")
$price = $json.IntOf("price")
$i = 0
$count_i = $json.SizeOfArray("tags")
while ($i -lt $count_i) {
$json.I = $i
$strVal = $json.StringOf("tags[i]")
$i = $i + 1
}
I'm having a little trouble finding the index of a hashtable in an array. I create a JSON with this code:
$start = {
Clear-Host
$BIB = Read-Host 'Bibliothek'
$BIBName = Read-Host 'Bibliothek Name'
$Standort = Read-Host 'Bibliothek Standort'
$Autor = Read-Host 'Buchautor'
$BuchName = Read-Host 'Buchname'
$jsonfile = "C:\Skripte\bibV2-1000.xml"
if(![System.IO.File]::Exists($jsonfile)){
$Data = #{BIBs = #(
#{$BIB = #{BIBName=$BIBName},
#{Standort = $Standort},
#{Bücher = #(
#{BuchName = $BuchName;
Autor = $Autor})
}}
)}
ConvertTo-Json -Depth 50 -InputObject $Data | Add-Content $jsonfile
.$continue
} else {
$jsonfile = "C:\Skripte\bibV2-1000.json"
$Data = Get-Content $jsonfile | ConvertFrom-Json
$Data.BIBs += New-Object -TypeName psobject -Property #{$BIB =
#{BIBname=$BIBName},
#{Standort=$Standort},
#{Bücher = #(#{
Buchname=$BuchName;
Autor=$Autor})
}
}
ConvertTo-Json -Depth 50 -InputObject $Data | Out-File $jsonfile}
.$continue
}
$continue = {
Write-Host ""
Write-Host "Was wollen Sie machen?"
Write-Host "(1) Eine weitere Bibliothek hinzufügen"
Write-Host "(2) Einer Bibliothek neue Bücher hinzufügen"
Write-Host "(E) Script beenden"
If (($read = Read-Host ) -eq "1") {
&$start} else {
if (($read) -eq "2") {
. C:\Skripte\büc.ps1 } else {
if (($read) -eq "E") {
exit} else {
Write-Host "+++ FALSCHE EINGABE! Bitte wählen Sie (1) oder (2) für die entsprechende Aktion +++"
.$continue
}
}
}
}
&$start
The output is as follows:
{
"BIBs": [{
"BIB1": [{
"BIBName": "123"
},
{
"Standort": "123"
},
{
"Bücher": [{
"Autor": "123",
"BuchName": "123"
}]
}
]
},
{
"BIB2": [{
"BIBname": "345"
},
{
"Standort": "345"
},
{
"Bücher": [{
"Autor": "345",
"Buchname": "345"
}]
}
]
}
]
}
Now I want to find out the index of "BIB1". I already tried the IndexOf()-Method which should create the output "0" but it gives me "-1" instead, because it can't find the value. How can I get the index of "BIB1"?
Judging by your earlier question, you're attempting to get the index of a specific object so you can access it via its containing array. However, you can do this more directly: $objOfInterest = $Data.BIBs | ? BIB1 - see my answer to your earlier question for details.
You need to iterate over the array elements of $Data.BIBs, which - on reading your serialized-to-a-file-as-JSON hashtables back in with ConvertFrom-Json - are custom objects (as Ansgar correctly points out; they are instances of [System.Management.Automation.PSCustomObject]), and check each for the presence of property 'BIB1':
(In a hashtable, you'd check for the presence of key 'BIB1' with .ContainsKey('BIB1'))
To test the existence of an object property, you need reflection, which is most easily - but somewhat obscurely - achieved via the hidden .PSObject property, as demonstrated in Ansgar Wiechers' more elegant solution.
However, given that the properties of interest have nonempty values, we can infer from the presence of a nonempty value that a given property exists, using implicit Boolean (logic): $obj.'BIB1' by default returns $null if there is no BIB1 property, which is "falsy" in a Boolean context such as an if conditional; conversely, any nonempty value is "truthy":
$propName = 'BIB1'
$i = $ndx = -1
foreach ($obj in $Data.BIBs) {
++$i
if ($obj.$propName) { $ndx = $i; break}
}
$ndx # $ndx now contains the index of the target object or -1 if there was no match
$Date.BIBs is an array of custom objects, not hashtables (since you wrote your original data to a JSON file and then converted that back), so you need something like this:
$arr = $Data.BIBs | ForEach-Object { $_.PSObject.Properties.Name }
$arr.IndexOf('BIB1') # returns 0
$arr.IndexOf('BIB2') # returns 1
Given that I am processing the following $json variable, how would I grab each server id (i.e. 215d1109-216d-48c3-af8e-998bb9bc3ca0 and 440cf918-3ee0-4143-b289-f63e1d2000e6 in this case) and put it into an array?
Right now $obj.servers.id returns nothing (as expected), but $obj.servers.id[0] returns an error message.
clear
[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") | out-null
$json = '
{
"servers": [
{
"admin_password": "qpYU66rKxmnK",
"id": "215d1109-216d-48c3-af8e-998bb9bc3ca0",
"links": [
{
"href": "http://openstack.example.com/v3/servers/<id>",
"rel": "self"
},
{
"href": "http://openstack.example.com/servers/<id>",
"rel": "bookmark"
}
]
},
{
"admin_password": "wfksH3GTTseP",
"id": "440cf918-3ee0-4143-b289-f63e1d2000e6",
"links": [
{
"href": "http://openstack.example.com/v3/servers/<id>",
"rel": "self"
},
{
"href": "http://openstack.example.com/servers/<id>",
"rel": "bookmark"
}
]
}
]
}
'
$ser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$obj = $ser.DeserializeObject($json)
$obj.servers.id;
Please note that I am using Powershell 2.0.
You're misunderstanding the structure of your data. $obj.servers is an array with two fields, each of which contains a dictionary, not an object containing an array id. You need to make the index access like this:
$obj.servers[0].id
$obj.servers.id[0] will certainly throw an error, because the array object $obj.servers doesn't have a property id, so in PowerShell v2 $obj.servers.id returns $null, and index access on a null array fails (as you'd expect).
Demonstration:
PS C:\> [void][Reflection.Assembly]::LoadWithPartialName('System.Web.Extensions')
$json = #'
...
'#
PS C:\> $ser = New-Object Web.Script.Serialization.JavaScriptSerializer
PS C:\> $obj = $ser.DeserializeObject($json)
PS C:\> $obj.servers.GetType().FullName
System.Object[]
PS C:\> $obj.servers.id -eq $null
True
PS C:\> $obj.servers[0].GetType().Name
Dictionary`2
PS C:\> $obj.servers[0] | Format-Table -AutoSize
Key Value
--- -----
admin_password qpYU66rKxmnK
id 215d1109-216d-48c3-af8e-998bb9bc3ca0
links {System.Collections.Generic.Dictionary`2[System.Str...
PS C:\> $obj.servers[0].id
215d1109-216d-48c3-af8e-998bb9bc3ca0
To extract all IDs simply pipe the array into a ForEach-Object loop where you echo the id property:
PS C:\> $ids = $obj.servers | % { $_.id }
PS C:\> $ids
215d1109-216d-48c3-af8e-998bb9bc3ca0
440cf918-3ee0-4143-b289-f63e1d2000e6