PowerShell将CSV转换为嵌套的Json

时间:2020-09-22 13:33:04

标签: json powershell csv nested

我尝试创建一个脚本,将csv文件中提供的数据导入API,为此,必须将CSV的每一行都转换为Json,然后发布到API。

我在csv中的基本数据如下:

Users.Name,Users.Mail,Users.AdditionalInfo.String1,Users.AdditionalInfo.Int1
System.String,System.String,System.String,System.Int32
MyName,my@name.com,Hello,1
YourName,your@name.com,GoodBye,2

第一行包含Json信息,其中“用户”是写入数据的API资源。 “用户”也可以是可通过API访问的任何其他对象,请参阅下面的评论。

第二行是标识值的类型。这是供以后使用,现在不使用,从第三行开始是数据。

“。”用于指定嵌套的“级别”,因此第一个为“。”。将API对象与json中的第一层(第二个“。”)分开。从第二级开始。

我希望这样返回Json:

{
    "Name": "MyName",
    "Mail": "my@mail.com",
    "AdditionalInfo": {
        "String1": "Hello",
        "Int1": 1
    }
}

我使用以下代码:

$objects = Import-Csv "test.csv" -Encoding UTF8
$validObjects = $objects | Select-Object -Skip 1
$validObjects

ForEach ($object in $validObjects) {
    
    #$apiObject = ($object.psobject.properties.name).Split(".")[0]
    $jsonObject = @{}

    ForEach ($property in $object.psobject.properties) {
       
       switch($property.Name.Split(".").Count - 1) {
            1 {
                $jsonObject.Add($property.Name.Split(".")[1], $property.Value)        
            }
            2 {
                $tempJsonObject = @{$property.Name.Split(".")[2] =  $property.Value}            
                $jsonObject.Add($property.Name.Split(".")[1], $tempJsonObject)        
            }
        }   
    }

    $jsonObject | ConvertTo-Json
    #@($object.psobject.properties).Count
}

我现在面临的问题是,由于我有两个以“ Users.AdditionalInfo”开头的列,因此会遇到错误,因为您只能一次将“ AdditionalInfo”添加为键。有没有简便的解决方法?

1 个答案:

答案 0 :(得分:1)

以这种方式设置它似乎非常疯狂。当然,XML将是满足需求的更好格式。就是说,这就是我想出的。

设置示例文件,以便其他人可以自己尝试。

$tempfile = New-TemporaryFile

@'
Users.Name,Users.Mail,Users.AdditionalInfo.String1,Users.AdditionalInfo.Int1
System.String,System.String,System.String,System.Int32
MyName,my@name.com,Hello,1
YourName,your@name.com,GoodBye,2
'@ | Set-Content $tempfile -Encoding utf8

$csvdata = Import-Csv $tempfile | select -skip 1

现在这是我的疯狂剧本

$csvdata | foreach {
    $ht = [ordered]@{}
    ,@($_.psobject.properties) | foreach {
        $subprops,$props = $_.where({$_.name -match 'additionalinfo'},'split')
        $props | foreach {$ht.Add($_.name,$_.value)}
        ,@($subprops) | foreach {
            $ht.Add("AdditionalInfo",(@{
                ($_[0].name.split(".")[2]) = $_[0].value
                ($_[1].name.split(".")[2]) = $_[1].value
            }))
        }
    }
    $ht
} | ConvertTo-Json -OutVariable jsonresults

显示的输出加存储在$jsonresults

[
    {
        "Users.Name":  "MyName",
        "Users.Mail":  "my@name.com",
        "AdditionalInfo":  {
                               "String1":  "Hello",
                               "Int1":  "1"
                           }
    },
    {
        "Users.Name":  "YourName",
        "Users.Mail":  "your@name.com",
        "AdditionalInfo":  {
                               "String1":  "GoodBye",
                               "Int1":  "2"
                           }
    }
]

我确定我从mklement或Mathias那里得到了两次使用的技巧是

,@(some objects that normally get passed one by one) | foreach

添加逗号和数组构造时,它一次将所有元素一一传递。在某些时候非常有帮助,例如肯定可以的。

我要强调的另一个技巧是此行

$subprops,$props = $_.where({$_.name -match 'additionalinfo'},'split')

where方法有几种模式,一种被拆分。任何与附加变量匹配的变量都移到第一个变量,其余变量移到第二个变量。希望这可以帮助您完成项目。

修改

由于诸如addrativeinfo之类的项可能随子属性的数量不同而有所不同,因此这里是一个可以容纳的版本。

$csvdata | foreach {
    $ht = [ordered]@{}
    ,@($_.psobject.properties) | foreach {
        $subprops,$props = $_.where({($_.name.split("."))[2]},'split')
        $props | foreach {$ht.Add($_.name,$_.value)}
        $subs = $subprops | foreach {$_.name.split(".")[1]} | Select -Unique
        foreach($name in $subs)
        {
            ,@($subprops | where name -match $name) | foreach {
                $oht = [ordered]@{}
                $_ | foreach {$oht[$_.name.split(".")[2]] = $_.value}
                $ht.Add($name,$oht)
            }
        }
    }
    $ht
} | ConvertTo-Json -OutVariable jsonresults -Depth 5

第一个数据集输出

[
    {
        "Users.Name":  "MyName",
        "Users.Mail":  "my@name.com",
        "AdditionalInfo":  {
                               "String1":  "Hello",
                               "Int1":  "1"
                           }
    },
    {
        "Users.Name":  "YourName",
        "Users.Mail":  "your@name.com",
        "AdditionalInfo":  {
                               "String1":  "GoodBye",
                               "Int1":  "2"
                           }
    }
]

@'
Users.Name,Users.Mail,Users.AnotherPossibility.String1,Users.AnotherPossibility.Int1,Users.AnotherPossibility.Int2,Users.AdditionalInfo.String1,Users.AdditionalInfo.Int1
System.String,System.String,System.String,System.Int32,System.String,System.Int32
MyName,my@name.com,Hello,1,3,Bonjour,5
YourName,your@name.com,GoodBye,2,4,Adios,6
'@ | Set-Content $tempfile -Encoding utf8

第二数据集输出

[
    {
        "Users.Name":  "MyName",
        "Users.Mail":  "my@name.com",
        "AnotherPossibility":  {
                                   "String1":  "Hello",
                                   "Int1":  "1",
                                   "Int2":  "3"
                               },
        "AdditionalInfo":  {
                               "String1":  "Bonjour",
                               "Int1":  "5"
                           }
    },
    {
        "Users.Name":  "YourName",
        "Users.Mail":  "your@name.com",
        "AnotherPossibility":  {
                                   "String1":  "GoodBye",
                                   "Int1":  "2",
                                   "Int2":  "4"
                               },
        "AdditionalInfo":  {
                               "String1":  "Adios",
                               "Int1":  "6"
                           }
    }
]