当前位置:  开发笔记 > 前端 > 正文

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

如何解决《通过Powershell中的变量解析/访问嵌套的JSON/Hashtable数据时出现问题》经验,为你挑选了1个好方法。

我正在尝试通过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/en-usdownload/details.aspx? id = 36389)要么.它可能在那里,我可能会错过它.

任何关于如何让Powershell与之相配的建议将不胜感激.我不确定Powershell如何/为什么使用简单的字符串,但似乎在这里遇到'something.somethingelse'类型字符串的问题.

谢谢.

原件的进一步说明和附录:

似乎有几个问题需要攻击.一个是"处理单个嵌套级别".对此的"快速修复"似乎是使用"Invoke-Expression"来解析语句,例如(重要 - 请注意第一个变量的后退!):

iex "`$MyPSJson.$NestedJsonPath"

使用Invoke-Expression也适用于多嵌套情况:

iex "`$MyPSJson.$LongNestedJsonPath"

提到的另一种方法是使用多个select语句......但是我无法使用多嵌套对象(Powershell似乎由于某种原因无法正确解决这些问题).

例如,在这种情况下:

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

Powershell回归

FirstLevel    
---------- 

...而不是实际的数据值.所以 - 现在,由于Powershell显然没有解决它们,所以选择似乎不适用于多级嵌套对象?



1> Joey..:

当你写的东西像

$MyPSJson.Name

这将尝试检索Name从该对象命名的成员$MyPSJson.如果没有这样的成员,你会得到$null.

现在,当您使用成员名称的变量执行此操作时:

$MyPSJson.$ShortJsonPath

这个工作非常相同,因为$ShortJsonPath查找存储有名称的成员并检索其值.这里没有惊喜.

当您尝试使用对象上不存在的成员时,例如

$MyPSJson.$NestedJsonPath
# equivalent to
# $MyPSJson.'NestedJSON.Version'

你会得到的$null,如前所述.的.操作者将只访问该确切的对象是其左手侧表达式的结果的成员.它永远不会以您期望它的方式通过成员层次结构.坦率地说,我不知道一种语言是这样运作的.

它的工作原理Invoke-Expression是,您有效地将$NestedJsonPath字符串转换为表达式的一部分,从而导致:

$MyPSJson.NestedJSON.Version

Invoke-Expression再评估.

当然,您可以定义自己的功能,这样就可以使用这种方式(而且我更喜欢使用Invoke-Expression,而不是使用cmdlet,这应该很少,如果曾经使用过的话(哎呀,它eval适用于PowerShell - 很少有语言使用eval它的主张) ):

function Get-DeepProperty([object] $InputObject, [string] $Property) {
  $path = $Property -split '\.'
  $obj = $InputObject
  $path | %{ $obj = $obj.$_ }
  $obj
}

PS> Get-DeepProperty $MyPSJson NestedJson.Version
5,0

你甚至可以把它变成一个过滤器,这样你就可以在管道上更自然地使用它:

filter Get-DeepProperty([string] $Property) {
  $path = $Property -split '\.'
  $obj = $_
  $path | %{ $obj = $obj.$_ }
  $obj
}

PS> $MyPSJson | Get-DeepProperty nestedjson.version
5,0

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有