我尝试创建一个脚本,将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”添加为键。有没有简便的解决方法?
答案 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"
}
}
]