【问题标题】:How to traverse through JSON data structure in PowerShell?如何在PowerShell中遍历JSON数据结构?
【发布时间】:2021-04-06 08:31:54
【问题描述】:

我是 PowerShell 的新手,从 Python 背景中快速学习它。

我正在从另一个通过 REST 调用检索数据的工具中提取数据。

METERS 变量以这种格式存储在源中。

{
    "500 HR": 500,
    "1000 HR": 1000,
    "2000 HR": 2000
}

PowerShell 代码

#REST call to source
$meter=@{}
Foreach ($item in $origresult.Items)  {
$result = (Invoke-RestMethod -Uri $url  -Headers $headers -Method GET -ContentType application/json -ErrorVariable RespErr)
$meter.Add($item.Name,$result.Value)
}
Write-Host ($meter | Out-String) -ForegroundColor Red

这是输出

Name                           Value
----                           -----
LastUploaded                   2020-12-29T06:38:02
IsEnabled                      1       
METERS                         {...
ORGID                          WHS

如何检索 METERS 并遍历字典?到目前为止我试过这个。 Python 以其简单的数据结构宠坏了我,PowerShell 并不是那么简单,除非有更简单的方法来做到这一点。

$mymeters = $meter.METERS | ConvertFrom-Json
Write-Host ($mymeters | Out-String) -ForegroundColor Yellow

输出

500 HR   : 500
1000 HR  : 1000
2000 HR  : 2000

这是我迄今为止尝试过的一些东西 -

$mymeters = [ordered]@{}
" Here is the item $mymeters.Get_Item(500 HR)" #my silly attempt!
# Looping is a no go either - it says specialized ordered dictionary
foreach ($ind in $mymeters) {
" --> $ind"
}

输出

 Here is the item System.Collections.Specialized.OrderedDictionary.Get_Item(500 HR)
 --> System.Collections.Specialized.OrderedDictionary

我可能遗漏了一些真正基本的东西,但我无法自己弄清楚!非常感谢任何帮助。我想要的只是遍历 METERS 哈希表/字典并调用一个函数。

【问题讨论】:

    标签: python powershell dictionary hashtable powershell-5.0


    【解决方案1】:

    在深入了解它之前,让我们回顾一些 PowerShell 语法基础知识,看看我们是否可以重用您的一些 Python 直觉:)

    会员访问

    就像在 Python 中一样,您可以使用 . 成员访问运算符通过 name 引用对象的属性 - 对于不连续的名称,请使用引号:

    $mymeters = $meter.METERS | ConvertFrom-Json
    $mymeters.'500 HR'  # evaluates to `500`
    

    字符串表达式

    PowerShell 中的字符串文字有两种不同的风格:

    • 单引号字符串 ('Hello World!')
      • 这些是逐字字符串文字,唯一支持的转义序列是''(文字单引号)
    • 双引号字符串 ("Hello World!")
      • 这些是 可扩展 字符串文字 - 除非显式转义,否则 $variable 标记和 $() 子表达式的自动插值将发生 - ` 是转义字符,以及您期望的常见序列大多数类 C 语言(`n`t`r 等)都能被原生识别。

    但是,任意表达式(如 $dictionary.get_Item('some key')不会按原样计算。

    要解决这个问题,我们可以使用-f 字符串格式运算符:

    $mymeters = [ordered]@{}
    "Here is item '500 HR': {0}" -f $mymeters['500 HR']
    

    -f 如果您习惯了 Python3 的 f 字符串,应该会感到熟悉,但需要注意的是 - PowerShell 的 -f 运算符是 String.Format()String.Format() 的薄包装器支持基于 0 的占位符 - '{0} {1}' -f 1,2 有效,但 '{} {}' -f 1,2 无效。

    另一种选择是将表达式包装在双引号字符串文字内的 $() 子表达式运算符中:

    $mymeters = [ordered]@{}
    "Here is item '500 HR': $($mymeters['500 HR'])"
    

    请注意,PowerShell 中的字典支持使用 [] 进行键控索引访问 - 就像 Python :)


    与 Python 不同,PowerShell(和一般的 .NET)也具有强大的内省功能。

    动态发现和迭代任何对象的属性就像引用一个名为 psobject 的特殊成员一样简单:

    foreach($propertyMetadataEntry in $someObject.psobject.Properties){
        "Property: {0,-20} = {1}" -f $propertyMetadataEntry.Name,$propertyMetadataEntry.Value
    }
    

    或者在你的情况下:

    $mymeters = $meter.METERS | ConvertFrom-Json
    foreach($meterReading in $mymeters.psobject.Properties){
        "Meter: {0,-20} = {1}" -f $meterReading.Name,$meterReading.Value
    
        # do whatever else you please with $meterReading here :)
    }
    

    这适用于任何标量对象(如ConvertFrom-JsonInvoke-RestMethod返回的对象)。

    要遍历字典中的条目,您需要显式调用.GetEnumerator()

    $dictionary = [ordered]@{ A = 1; B = 2; C =3 }
    foreach($keyValuePair in $dictionary.GetEnumerator()){
        "Dictionary Entry: {0} = {1}" -f $keyValuePair.Key,$keyValuePair.Value
    }
    

    【讨论】:

    • 非常感谢您提供的基础知识和 101,与 Python 相比,确实有助于理解细微差别。当我尝试你的方法时我仍然得到这个 - Meter: Count = 0 Meter: IsReadOnly = False Meter: Keys = System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection Meter: Values = System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection Meter: IsFixedSize =错误仪表:SyncRoot = System.Object 仪表:IsSynchronized = False
    • 那些有序字典对象的属性(就像[ordered]@{}产生的那个)。如果您想要字典中的条目,则需要获取一个枚举器:foreach($kvp in $dictionary.GetEnumerator()){ $kvp.Key,$kvp.Value -join '='}
    • $mymeters = $meter.METERS | ConvertFrom-Json foreach($kvp in $mymeters.GetEnumerator()) { " --> I got here
    • 反过来 - ConvertFrom-Json 返回一个 [PSCustomObject],您需要针对它迭代 .psobject.Properties。另一方面,[ordered]@{} 返回一个有序字典 - 对于 字典,您需要 GetEnumerator()
    • 啊,成功了,非常感谢!我按照你的建议使用了这个 foreach($meterReading in $mymeters.psobject.Properties)。
    【解决方案2】:

    请在下面查看我的答案:

    1.) 我在 powershell 5.x 上测试了这些东西。新旧版本的 powershell(尤其是旧版本)可能会略有不同

    2.) Invoke-Restmethod 会自动将 json 响应转换为 powershell 对象,因此无需进一步处理。把所有的赋值去掉到一个哈希表中。

    $responseJson = '{
        "500 HR": 500,
        "1000 HR": 1000,
        "2000 HR": 2000
    }'
    
    $response = $responseJson | ConvertFrom-Json
    
    $nodes = (Get-Member -inputobject $response  -MemberType NoteProperty).Name
    
    $nodes | ForEach-Object {
        echo ("Element: $_ Result: " +$response.$_)
        
    }
    
    echo "Another one"
    
    #alternative
    foreach ($node in $nodes) {
        echo ("Element: $node Result: " +$response.$node)
    }
    

    3.) 我认为响应格式不正确,因此如果您可以控制其余服务,我建议您这样做:

    $responseJson = '{
        "hr": [
         500,
        1000,
        2000
        ]
    }'
    
    $response = $responseJson | ConvertFrom-Json
    
    $response.hr | ForEach-Object {
        echo ("Element: $_ Result: " +$response.$_)
        
    }
    
    

    【讨论】:

    • 我确实对源有一些控制权,可以更改 METERS 具有 JSON 字符串的方式。我需要键、值对、一些边缘情况,如 12KHR: 12000 等。我能够使用您的节点逻辑遍历仪表。我将其作为您提供的两个选项的输出 - 例如。元素:500 HR 结果:,我可以得到键值输出吗? $response.$node 或 $response.$_ 为空白。
    • 嗨,密钥在 $node 中,值在 $response.node 中,或者我缺少什么?
    • 我很抱歉,变量搞砸了。这也奏效了。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多