如何使用 Powershell 遍历 JSON 属性



我正在尝试使用Powershell访问JSON对象的特定属性值。不幸的是,我不知道结构中某些父属性的键,因此我无法以直接的方式执行此操作。另外,由于 JSON 不是数组,我无法通过索引位置访问。

上下文是我正在从 elasticsearch 查询正在运行的任务列表,并且需要获取任务的 ID(我知道只有一个(,以便我可以进行后续调用以发现其完成状态。

我已经研究了一些查询方法,但不确定如何应用它们(PowerShell 语法对我来说很新(。

我正在使用的 JSON 响应如下所示;

"nodes" : {
"oTUltX4IQMOUUVeiohTt8A" : {
"name" : "H5dfFeA",
"transport_address" : "127.0.0.1:9300",
"host" : "127.0.0.1",
"ip" : "127.0.0.1:9300",
"tasks" : {
"oTUltX4IQMOUUVeiohTt8A:124" : {
"node" : "oTUltX4IQMOUUVeiohTt8A",
"id" : 124,
"type" : "direct",
"action" : "cluster:monitor/tasks/lists[n]",
"start_time_in_millis" : 1458585884904,
"running_time_in_nanos" : 47402,
"cancellable" : false,
"parent_task_id" : "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}

有了这个给定的结构,我希望能够访问第一个"任务"的 ID 属性。

因此,如果我知道道具键,那就是:

nodes.oTUltX4IQMOUUVeiohTt8A.tasks.oTUltX4IQMOUUVeiohTt8A:124.id

如何在事先不知道密钥的情况下访问此值?

任何帮助非常感谢。

谢谢 缺口

以下代码定义并使用函数Get-FirstPropertyValue,该函数对具有给定名称的对象图中的第一个属性执行递归深度优先搜索,并返回其值,假设该值为非空:

# Function that returns the value of the first property with the given 
# name found during recursive depth-first traversal of the given object.
# Note that null-valued properties are ignored.
function Get-FirstPropertyValue($obj, $propName) {
$propNames = $obj.psobject.properties.Name
if ($propName -in $propNames) {
$obj.$propName
} else {
foreach ($iterPropName in $propNames) {
if ($null -ne ($val = Get-FirstPropertyValue $obj.$iterPropName $propName)) {
return $val
}
}
}
}
# Input JSON
$json = @'
{
"nodes": {
"oTUltX4IQMOUUVeiohTt8A": {
"name": "H5dfFeA",
"transport_address": "127.0.0.1:9300",
"host": "127.0.0.1",
"ip": "127.0.0.1:9300",
"tasks": {
"oTUltX4IQMOUUVeiohTt8A:124": {
"node": "oTUltX4IQMOUUVeiohTt8A",
"id": 124,
"type": "direct",
"action": "cluster:monitor/tasks/lists[n]",
"start_time_in_millis": 1458585884904,
"running_time_in_nanos": 47402,
"cancellable": false,
"parent_task_id": "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
'@
# Convert the JSON to a [pscustomobject] graph with ConvertFrom-Json.
$objFromJson = $json | ConvertFrom-Json
# Using the function defined above, get the first 'tasks' object found
# during recursive depth-first traversal.
$tasks = Get-FirstPropertyValue $objFromJson 'tasks'
# Get the name of the resulting object's first property.
$propName = @($tasks.psobject.properties.Name)[0]
# Extract the .id property from the object stored in the first property.
$tasks.$propName.id

以上结果:

124

一种更简洁,但更晦涩且可能更慢的替代方法是将 JSON 输入转换为 XML,然后使用XPath进行查询:

# Input JSON
$json = @'
{
"nodes": {
"oTUltX4IQMOUUVeiohTt8A": {
"name": "H5dfFeA",
"transport_address": "127.0.0.1:9300",
"host": "127.0.0.1",
"ip": "127.0.0.1:9300",
"tasks": {
"oTUltX4IQMOUUVeiohTt8A:124": {
"node": "oTUltX4IQMOUUVeiohTt8A",
"id": 124,
"type": "direct",
"action": "cluster:monitor/tasks/lists[n]",
"start_time_in_millis": 1458585884904,
"running_time_in_nanos": 47402,
"cancellable": false,
"parent_task_id": "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
'@
$parent = 'tasks'
$prop = 'id'
$propType = 'int'
$json | 
ConvertFrom-Json |
ConvertTo-Xml -Depth ([int]::MaxValue) | 
Select-Xml "//Property[@Name='$parent']/*/*[@Name='$prop']/text()" |
ForEach-Object { $_.Node.InnerText -as $propType }

我知道有两种方法可以实现这一点,两者都看起来有点粗糙。

对于这些示例,我将把您提供的 JSON 加载到$json中。

$json = @'
{
"nodes": {
"oTUltX4IQMOUUVeiohTt8A": {
"name": "H5dfFeA",
"transport_address": "127.0.0.1:9300",
"host": "127.0.0.1",
"ip": "127.0.0.1:9300",
"tasks": {
"oTUltX4IQMOUUVeiohTt8A:124": {
"node": "oTUltX4IQMOUUVeiohTt8A",
"id": 124,
"type": "direct",
"action": "cluster:monitor/tasks/lists[n]",
"start_time_in_millis": 1458585884904,
"running_time_in_nanos": 47402,
"cancellable": false,
"parent_task_id": "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
'@ | ConvertFrom-Json

第一种是使用Select-Object选择第一项,然后展开属性。

(($json.nodes | Select-Object -First 1 -ExpandProperty *).tasks | Select-Object -First 1 -ExpandProperty *).id

一个更健壮的方法是使用隐藏的PSObject属性Value,因为JSON被PowerShell解析为PSCustomObject。

PS C:Windowssystem32> $json.nodes.GetType()
IsPublic IsSerial Name                                     BaseType                                                                                                                                                      
-------- -------- ----                                     --------                                                                                                                                                      
True     False    PSCustomObject                           System.Object  

.PSObject的特性

PS C:Windowssystem32> $json.nodes.PSObject.Properties

MemberType      : NoteProperty
IsSettable      : True
IsGettable      : True
Value           : @{name=H5dfFeA; transport_address=127.0.0.1:9300; host=127.0.0.1; ip=127.0.0.1:9300; tasks=}
TypeNameOfValue : Selected.System.Management.Automation.PSCustomObject
Name            : oTUltX4IQMOUUVeiohTt8A
IsInstance      : True

访问 ID 值的完整命令:

$json.nodes.PSObject.Properties.Value.tasks.PSObject.Properties.Value.id

最新更新