【发布时间】:2017-01-26 14:09:03
【问题描述】:
我正在尝试通过 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 的建议——但遗憾的是,这也有同样的问题。所以用上面的code-sn-p,下面会把JSON对象转换成hashtable。
# 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/en-usdownload/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 显然没有解决它们,因此选择似乎不适用于多级嵌套对象?
【问题讨论】:
-
Invoke-Expression 是最简单(我猜也是最慢)的解决方案:
iex "`$MyPSJson.$NestedJsonPath" -
我可以忍受慢 - 只要我能让它表现/开始工作。
-
-
仍然没有更接近理解 iex 为何有效,但 dot-walking 无效……但只想说(单独)非常感谢您让我摆脱这种束缚。您的建议完美适用于多层嵌套。 :)
标签: json powershell