说我有JSON,如:
{
"a" : {
"b" : 1,
"c" : 2,
}
}
现在ConvertTo-Json
会很高兴地从中创建PSObjects
。我想访问一个我可以做的项目$json.a.b
并获得1-很好地嵌套的属性。
现在,如果我有字符串"a.b"
,问题是如何使用该字符串访问该结构中的同一项目?似乎应该缺少一些特殊的语法,例如用于动态函数调用的&
,因为否则,您必须自己反复使用Get-Member
来解释字符串,我希望如此。
答案 0 :(得分:6)
否,没有 no 特殊语法。
最简单的解决方案是使用Invoke-Expression
,在这种受限制的情况下,这很好,但是Invoke-Expression
should generally be avoided:
$json = @'
{
"a" : {
"b" : 1,
"c" : 2,
}
}
'@
$obj = ConvertFrom-Json $json
# The path to the target property.
$propertyPath = 'a.b'
# Construct the expression and pass it to Invoke-Expression.
# Note the need to `-escape the `$` in `$obj` to prevent premature expansion.
Invoke-Expression "`$obj.$propertyPath"
以上等同于直接执行$obj.a.b.
并产生1
。
或者,您可以编写一个简单的 helper函数:
function propByPath($obj, $propertyPath) {
foreach ($prop in $propertyPath -split '\.') { $obj = $obj.$prop }
$obj # output
}
您将使用{p> 1代替Invoke-Expression
:
propByPath $obj $propertyPath
您甚至可以使用PowerShell的ETS (扩展类型系统)将.GetPropByPath()
方法附加到所有[pscustomobject]
实例( PSv3 + 语法;在PSv2中,您必须创建一个*.types.ps1xml
文件并使用Update-TypeData -PrependPath
加载它):
'System.Management.Automation.PSCustomObject',
'Deserialized.System.Management.Automation.PSCustomObject' |
Update-TypeData -TypeName { $_ } `
-MemberType ScriptMethod -MemberName GetPropByPath -Value { #`
param($propPath)
$obj = $this
foreach ($prop in $propPath -split '\.') { $obj = $obj.$prop }
$obj # output
}
然后您可以呼叫$obj.GetPropByPath('a.b')
。
注意:除Deserialized.System.Management.Automation.PSCustomObject
之外,还以类型System.Management.Automation.PSCustomObject
为目标,以便涵盖以数字形式返回的反序列化自定义对象场景,例如使用Import-CliXml
,从后台作业接收输出以及使用远程处理。
.GetPropByPath()
将在其余会话中的任何[pscustomobject]
实例上可用(甚至在Update-TypeData
调用 [1] 之前创建的实例上) ;将Update-TypeData
调用放入您的$PROFILE
(配置文件)中,以使该方法默认可用。
一种更强大的解决方案,它支持索引并保留数组值属性
以上解决方案:
'a.b[2]'
)以下解决方案解决了这些限制,但请注意:
仅支持文字标量索引(例如,您可以使用'a.b[2]'
,但不能使用'a.b[1..2]'
或'a.b[1, 2]'
)
对于作为哈希表的属性,请指定(文字)键名称,而无需嵌入引号(例如'a.ht[bar]'
);请注意,通常您将无法访问数字哈希表键,此外,您将无法通过访问有序哈希表的条目索引。
'System.Management.Automation.PSCustomObject',
'Deserialized.System.Management.Automation.PSCustomObject' |
Update-TypeData -TypeName { $_ } `
-MemberType ScriptMethod -MemberName GetPropByPath -Value { #`
param($propPath)
$obj = $this
foreach ($prop in $propPath -split '\.') {
# See if the property spec has an index (e.g., 'foo[3]')
if ($prop -match '(.+?)\[(.+?)\]$') {
$obj = $obj.($Matches.1)[$Matches.2]
} else {
$obj = $obj.$prop
}
}
# Output: If the value is a collection (array), output it as a
# *single* object.
if ($obj.Count) {
, $obj
} else {
$obj
}
}
[1]使用$co = New-Object PSCustomObject; Update-TypeData -TypeName System.Management.Automation.PSCustomObject -MemberType ScriptMethod -MemberName GetFoo -Value { 'foo' }; $co.GetFoo()
(全部在一行上)进行验证,即使在调用foo
之前创建了$co
,它也会输出Update-TypeData
。