2

我正在从 json 文件制作 PSObject

bar.json

{
  "derp": {
   "buzz": 42 
   },
   "woot":  {
     "toot": 9000
   }
}

我可以使用 ConvertFrom-Json 从 json 中创建一个 PSCustomObject

$foo = Get-Content .\bar.json -Raw |ConvertFrom-Json
$foo.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

但是,如果我尝试分解多个 json 文件,我会得到一个数组

$foo = Get-Content .\*.json -Raw |ConvertFrom-Json
$foo.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    Object[]                                 System.Array

为了迭代 $foo,我需要 2 个不同的代码路径,具体取决于对象类型。

我可以从多个 json 文件中获取单个对象吗?
如果不是,我将如何将一组对象压缩成一个对象?

我试图制作一个$bar包含所有数组项的新对象$foo

$bar = new-object psobject
$bar | add-member -name $foo[0].psobject.properties.name -value $foo[0].'derp' -memberType NoteProperty


根据 Walter Mitty 的要求更新。如果我加载一个文件并运行$foo[0]

$foo = Get-Content .\bar.json -Raw |ConvertFrom-Json
$foo[0].gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

$foo[0]

derp                                                    woot
------------                                            ------------
@{Provisioners=System.Object[]; OS=windows; Size=; V... @{Provisioners=System.Object[]; OS=windows; Size=; V...

解决方案

我最初实现了 AP 的答案,但后来将其重构为使用 mklement0 答案。

虽然 $allObjects 是一个数组,但它仍然允许我按名称引用值,这是我正在寻找的

$allObjects = @(
    Get-ChildItem '.\foo' -Filter *.json -Recurse | Get-Content -Raw | ConvertFrom-Json
)

# iterating over nested objects inside an array is hard.
# make it easier by moving all array objects into 1 parent object where 
# the 'key' is the name (opposed to AP's answer where filename = key)
$newObject = New-Object PSObject
foreach ($i in $allObjects) {
    $i.psobject.members | ?{$_.Membertype -eq 'noteproperty'} |%{$newObject | add-member $_.Name $_.Value}
}
4

2 回答 2

3

如果你想要的只是一个从不同文件中解析出来的 JSON 对象数组:

$final = @{}

# Loop Thru All JSON Files, and add to $Final[<name>] = <JSON>
ls .\*.json | % {
  $o = cat $_ -Raw | ConvertFrom-Json
  $final[$_.name] = [PsCustomObject]$o
}
$final = [PsCustomObject]$final

这将为您的所有 JSON 文件生成一个名称 -> 数据映射作为嵌套PSObject

于 2016-12-09T18:23:04.943 回答
2

AP. 的有用答案是创建单个顶级对象([pscustomobject]实例)的优雅解决方案:

  • 将所有 JSON 转换的对象作为以其输入文件名命名的属性

    • 例如,$final将包含一个bar.json属性,其值是问题中 JSON 字符串的对象等价物。

    • 需要注意的是,如果文件名重复,最后处理的文件将“获胜”。

有关 Unix 样式别名lscat.


获取所有转换自 JSON 对象的数组,以下内容就足够了:

$allObjects = @(Get-ChildItem -Filter *.json | Get-Content -Raw | ConvertFrom-Json)

请注意,如果您只需要一个目录的 JSON 文件,
$allObjects = @(Get-Content -Path *.json -Raw | ConvertFrom-Json)也可以。

请注意数组@(...)子表达式运算符的使用,它确保返回的内容被视为数组,即使只返回一个对象

  • 默认情况下,或者当您使用$(...)子表达式运算符时,PowerShell 会展开任何(可能嵌套的)单项集合并仅返回项本身;见Get-Help about_Operators

关于使用 Unix 样式别名ls以及catPowerShellGet-ChildItemGet-Contentcmdlet 的注释:

  • 现在 PowerShell 是跨平台的,这些别名仅存在于Windows版本的 PowerShell 中,而决定从 Unix 平台上的 PowerShell Core 中省略它们,以免影响同名的标准 Unix 实用程序。

  • 最好养成使用 PowerShell自己的别名的习惯,这些别名遵循规定的命名约定并且不与特定于平台的实用程序冲突。

    • 例如,gci可以用于Get-ChildItemgcforGet-Content
    • 有关 PowerShell 自己的别名背后的命名约定,请参阅文档
于 2016-12-09T21:21:07.427 回答