小编典典

通过Powershell中的变量解析/访问嵌套的JSON /哈希表数据时出现问题

json

我正在尝试通过Powershell动态解析和构建一些我将要提供的传入JSON文件的数据结构(将采用非标准结构),然后处理这些文件中的数据并交给他们转到下一步。

作为其中的一部分,我正在尝试将JSON文件的数据结构构建为实质上的数据路径列表,以便我解析并从中获取数据,以便可以处理嵌套JSON的数组。对象等。到目前为止,一切都很好。

我遇到某种Powershell特性的地方是通过变量处理2级以上的深度。让我给你一个漂亮的代码块来演示这个问题…

# Generate a Quick JSON file with different data types & levels
[object]$QuickJson = @'
{
    "Name" : "I am a JSON",
    "Version" : "1.2.3.4",
    "SomeBool" : true,
    "NULLValue" : null,
    "ArrayOfVersions" : [1.0,2.0,3.0],
    "MyInteger" : 69,
    "NestedJSON" : {
        "Version" : 5.0,
        "IsReady" : false
    },
    "DoubleNestedJSON" : {
        "FirstLevel" : 1,
        "DataValue" : "I am at first nested JSON level!",
        "Second_JSON_Level" : {
            "SecondLevel" : 2,
            "SecondDataValue" : "I am on the 2nd nested level"
        }
    }
}
'@

# Import our JSON file into Powershell
[object]$MyPSJson = ConvertFrom-Json -InputObject $QuickJson
# Two quick string variables to access our JSON data paths
[string]$ShortJsonPath = "Name"
[string]$NestedJsonPath = "NestedJson.Version"
# Long string to access a double-nested JSON object
[string]$LongNestedJsonPath = "DoubleNestedJSON.Second_JSON_Level.SecondDataValue"

# Both of these work fine
Write-Host ("JSON Name (Direct) ==> " + $MyPSJson.Name)
Write-Host ("JSON Name (via Variable) ==> " + $MyPSJson.$ShortJsonPath)

# The following way to access a single nested Json Path works fine
Write-Host ("Nested JSON Version (via direct path) ==> " + $MyPSJson.NestedJson.Version)
# And THIS returns an empty line / is where I fall afoul of something in Powershell
Write-Host ("Nested JSON Version (via variable) ==> " + $MyPSJson.$NestedJsonPath)

# Other things I tried -- all returning an empty line / failing in effect
Write-Host ("Alternate Nested JSON Version ==> " + $($MyPSJson.$NestedJsonPath))
Write-Host ("Alternate Nested JSON Version ==> " + $MyPSJson.$($NestedJsonPath))
Write-Host ("Alternate Nested JSON Version ==> " + $($MyPSJson).$($NestedJsonPath))

# Similarly, while THIS works...
$MyPSJson | select-object -Property NestedJSON
# This will fail / return me nothing
$MyPSJson | select-object -Property NestedJSON.Version

…在对此进行了大量研究时,我遇到了一个将其转换为Hashtable的建议-
可悲的是,它存在相同的问题。因此,使用上面的代码片段,下面的代码会将JSON对象转换为哈希表。

# Same problem with a hash-table if constructed from the JSON file...
[hashtable]$MyHash = @{}
# Populate $MyHash with the data from our quickie JSON file...
$QuickJson | get-member -MemberType NoteProperty | Where-Object{ -not [string]::IsNullOrEmpty($QuickJson."$($_.name)")} | ForEach-Object {$MyHash.add($_.name, $QuickJson."$($_.name)")}

# ... and even then -- $MyHash."$($NestedJsonPath)" -- fails, while a single level deep string works fine in the variable! :(

因此,很明显,我遇到了Powershell内部逻辑问题的“某些方面”,但是我不能说Powershell在为什么如此方面过分帮助。添加“
-debug”或类似命令以增加详细程度并没有帮助我们弄清这一点。

我怀疑这类似于本文(https://blogs.technet.microsoft.com/heyscriptingguy/2011/10/16/dealing-
with-powershell-hash-table-
quirks/)中提出的内容与变量。

在Powershell语言规范中找不到任何明显的东西我没有运气(据我所知,3.0仍然是此处最新的东西)-https:
//www.microsoft.com/zh-cn/downloads/details.aspx? id =
36389)。它可能在那里,我可能会想念它。

任何有关如何使Powershell与其搭配使用的建议都将不胜感激。我不确定Powershell如何/为什么使用简单的字符串就可以,但是在这里似乎与’something.somethingelse’类型的字符串有关。

谢谢。

原件的其他说明和附录:

似乎有几个问题需要攻击。一种是“处理单个嵌套级别”。为此,“快速修复”似乎正在使用“ Invoke-Expression”来解析该语句,例如(重要-
注意第一个变量的反勾号!):

iex "`$MyPSJson.$NestedJsonPath"

使用Invoke-Expression还可用于多嵌套情况:

iex "`$MyPSJson.$LongNestedJsonPath"

提到的另一种方法是使用多个选择语句…但是我无法使它与多嵌套对象一起使用(Powershell出于某种原因似乎无法正确解析这些对象)。

因此,例如在这种情况下:

($MyComp | select $_.DoubleNestedJSON | select FirstLevel)

Powershell返回

FirstLevel    
----------

…而不是实际数据值。所以-目前看来,由于Powershell显然无法解决选择问题,因此selects不适用于多层嵌套对象吗?


阅读 370

收藏
2020-07-27

共1个答案

小编典典

为什么这不起作用

当您在字符串中提供所需的属性时,就像这样

[string]$NestedJsonPath = "NestedJson.Version"

Powershell寻找一个名为的属性NestedJSon.Version。它实际上并没有遍历属性,而是在寻找包含句点的字符串文字。实际上,如果我这样向您的JSON添加这样的属性。

[object]$QuickJson = @'
{
    "Name" : "I am a JSON",
    "Version" : "1.2.3.4",
    "SomeBool" : true,
    "NULLValue" : null,
    "ArrayOfVersions" : [1.0,2.0,3.0],
    "MyInteger" : 69,
    "NestedJSON.Version" : 69,
    "NestedJSON" : {
        "Version" : 5.0,
        "IsReady" : false
    }
}

我现在得到了价值,就像这样:

>$MyPSJson.$NestedJsonPath
69

取回值的最佳方法是使用两个单独的变量,如下所示。

$NestedJson = "NestedJson"
$property   = "Version"

>$MyPSJson.$NestedJson.$property
5.0

或者,您也可以使用select语句,如下面的原始答案所示。


$MyPSJson | select $_.NestedJSON | select Version
Version
-------
1.2.3.4

如果您使用多个Select-Object语句,它们将丢弃其他属性,并允许您更轻松地向下钻取您想要的值。

2020-07-27