Как просмотреть свойства JSON с помощью Powershell - PullRequest
2 голосов
/ 20 октября 2019

Я пытаюсь получить доступ к определенному значению свойства объекта JSON с помощью Powershell. К сожалению, я не знаю ключей некоторых родительских свойств в структуре, поэтому я не могу сделать это простым способом. Кроме того, поскольку JSON не является массивом, я не могу получить к нему доступ через индексную позицию.

Контекст заключается в том, что я запрашиваю список запущенных задач из эластичного поиска и мне нужно получить идентификатор задачи (я знаю, чтобудет только один), поэтому я могу сделать последующие вызовы, чтобы определить его состояние завершения.

Я исследовал некоторые методы запросов, но не уверен, как их применять (синтаксис 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

Как я могу получить доступ к этому значению, не зная заранее ключей?

Любая помощь очень ценится.

Спасибо, Ник

Ответы [ 2 ]

2 голосов
/ 21 октября 2019

Следующий код определяет и использует функцию 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

A более краткий, но более неясный и предположительно более медленный вариант означает преобразовать входные данные 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 }
0 голосов
/ 21 октября 2019

Есть два способа, которыми я знаю, что вы можете достичь этого, оба выглядят немного грубовато.

Для этих примеров я загружу предоставленный вами 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, поскольку PowerShell анализирует JSON в PSCustomObject.

PS C:\Windows\system32> $json.nodes.GetType()

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

Свойства .PSObject

PS C:\Windows\system32> $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

Полная команда для доступа к значению идентификатора:

$json.nodes.PSObject.Properties.Value.tasks.PSObject.Properties.Value.id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...