我正在尝试通过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显然没有解决它们,所以选择似乎不适用于多级嵌套对象?
当你写的东西像
$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