我正在尝试在 PowerShell 中遍历以下 JSON 文件。
没有具体命名顶部标签(例如 17443 和 17444),因为我事先不知道它们,所以我找不到循环数据的方法。
我想为所有记录输出标签 3、4 和 5(标题、名字、姓氏)。
我将如何做到这一点?
{
"17443":{
"sid":"17443",
"nid":"7728",
"submitted":"1436175407",
"data":{
"3":{
"value":[
"Mr"
]
},
"4":{
"value":[
"Jack"
]
},
"5":{
"value":[
"Cawles"
]
}
} },
"17444":{
"sid":"17444",
"nid":"7728",
"submitted":"1436891400",
"data":{
"3":{
"value":[
"Miss"
]
},
"4":{
"value":[
"Charlotte"
]
},
"5":{
"value":[
"Tann"
]
}
}
},
"17445":{
"sid":"17445",
"nid":"7728",
"submitted":"1437142325",
"data":{
"3":{
"value":[
"Mr"
]
},
"4":{
"value":[
"John"
]
},
"5":{
"value":[
"Brokland"
]
}
}
}
}
我可以使用下面的代码访问数据,但我想避免输入 17443、17444 等。
$data = ConvertFrom-Json $json
foreach ($i in $data.17443)
{
foreach ($t in $i.data.3)
{
Write-Host $t.value
}
foreach ($t in $i.data.4)
{
Write-Host $t.value
}
foreach ($t in $i.data.5)
{
Write-Host $t.value
}
}
最佳答案
PowerShell 3.0+
在 PowerShell 3.0 及更高版本(参见:Determine installed PowerShell version)中,您可以使用 ConvertFrom-Json
cmdlet 将 JSON 字符串转换为 PowerShell 数据结构。
这既方便又不幸——方便,因为很容易消费 JSON,不幸的是,ConvertFrom-Json
给你 PSCustomObjects ,并且它们很难作为键值对进行迭代。
当您知道 key 时,就没有什么可迭代的了 - 您只需直接访问它们,例如$result.thisKey.then.thatKey.array[1]
,你就完成了。
但在这个特定的 JSON 中,键似乎是动态的/提前不知道的,例如 "17443"
或 "17444"
。这意味着我们需要能够将 PSCustomObject
转换为 foreach
可以理解的键值列表的东西。
# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMember {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[PSCustomObject]$obj
)
$obj | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]@{Key = $key; Value = $obj."$key"}
}
}
现在我们可以遍历对象图并生成带有 Title
、FirstName
和 LastName
$json = '{"17443": {"17444": {"sid": "17444","nid": "7728","submitted": "1436891400","data": {"3": {"value": ["Miss"]},"4": {"value": ["Charlotte"]},"5": {"value": ["Tann"]}}},"17445": {"sid": "17445","nid": "7728","submitted": "1437142325","data": {"3": {"value": ["Mr"]},"4": {"value": ["John"]},"5": {"value": ["Brokland"]}}},"sid": "17443","nid": "7728","submitted": "1436175407","data": {"3": {"value": ["Mr"]},"4": {"value": ["Jack"]},"5": {"value": ["Cawles"]}}}}'
$json | ConvertFrom-Json | Get-ObjectMember | foreach {
$_.Value | Get-ObjectMember | where Key -match "^\d+$" | foreach {
[PSCustomObject]@{
Title = $_.value.data."3".value | select -First 1
FirstName = $_.Value.data."4".value | select -First 1
LastName = $_.Value.data."5".value | select -First 1
}
}
}
输出
Title FirstName LastName ----- --------- -------- Miss Charlotte Tann Mr John Brokland
PowerShell 2.0 / Alternative approach
An alternative approach that also works for PowerShell 2.0 (which does not support some of the constructs above) would involve using the .NET JavaScriptSerializer class to handle the JSON:
Add-Type -AssemblyName System.Web.Extensions
$JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer
现在我们可以做一个非常相似的操作——甚至比上面简单一点,因为 JavaScriptSerializer 给你常规的 Dictionaries ,很容易通过 GetEnumerator()
方法作为键值对进行迭代:
$json = '{"17443": {"17444": {"sid": "17444","nid": "7728","submitted": "1436891400","data": {"3": {"value": ["Miss"]},"4": {"value": ["Charlotte"]},"5": {"value": ["Tann"]}}},"17445": {"sid": "17445","nid": "7728","submitted": "1437142325","data": {"3": {"value": ["Mr"]},"4": {"value": ["John"]},"5": {"value": ["Brokland"]}}},"sid": "17443","nid": "7728","submitted": "1436175407","data": {"3": {"value": ["Mr"]},"4": {"value": ["Jack"]},"5": {"value": ["Cawles"]}}}}'
$data = $JS.DeserializeObject($json)
$data.GetEnumerator() | foreach {
$_.Value.GetEnumerator() | where { $_.Key -match "^\d+$" } | foreach {
New-Object PSObject -Property @{
Title = $_.Value.data."3".value | select -First 1
FirstName = $_.Value.data."4".value | select -First 1
LastName = $_.Value.data."5".value | select -First 1
}
}
}
输出是一样的:
Title FirstName LastName ----- --------- -------- Miss Charlotte Tann Mr John Brokland
如果您的 JSON 大于 4 MB,请设置 JavaScriptSerializer.MaxJsonLength
property相应地。
关于从文件中读取 JSON
如果从文件中读取,请使用 Get-Content -Raw -Encoding UTF-8
。
-Raw
因为否则Get-Content
返回一个单独的行数组,而JavaScriptSerializer.DeserializeObject
无法处理。最近的 Powershell 版本似乎改进了 .NET 函数参数的类型转换,因此它可能不会在您的系统上出错,但如果确实如此(或只是为了安全起见),请使用-Raw
。-Encoding
因为在读取文本文件时指定其编码是明智的,而UTF-8
是 JSON 文件最可能的值。
注意事项
- 当您构建包含具有不可预测键的项目的 JSON 时,更喜欢像
{items: [{key: 'A', value: 0}, {key: 'B', value: 1}] 这样的数组结构}
在{'A': 0, 'B': 1}
之上。后者似乎更直观,但它既难以生成,也更难以使用。 ConvertFrom-Json()
为您提供反射(reflect) JSON 字符串中数据的 PowerShell 自定义对象 (PSCustomObject
)。- 您可以使用
Get-Member -type NoteProperty
循环自定义对象的属性
- 您可以使用
$object."$propName"
语法或$object."$(some PS expression)"
动态访问对象的属性。 - 您可以创建自己的自定义对象并使用
New-Object PSObject -Property @{...}
或[PSCustomObject]@{ .. }
`
关于json - 遍历 JSON 文件 PowerShell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33520699/