【发布时间】:2016-04-14 13:13:31
【问题描述】:
默认情况下,PowerShell 的 ConvertFrom-Json cmdlet 似乎不处理 JSON 文档中的引用。
{
"foo": {"$ref": "#/bar"},
"bar": true
}
我真的不知道这个 JSON 规范的官方状态(参见 here 和 here),但是有没有办法在 PowerShell 中管理这样的事情?
【问题讨论】:
标签: json powershell
默认情况下,PowerShell 的 ConvertFrom-Json cmdlet 似乎不处理 JSON 文档中的引用。
{
"foo": {"$ref": "#/bar"},
"bar": true
}
我真的不知道这个 JSON 规范的官方状态(参见 here 和 here),但是有没有办法在 PowerShell 中管理这样的事情?
【问题讨论】:
标签: json powershell
AFAIK 没有内置的方法来解析 JSON 引用。我通常会寻找 C# 解决方案来解决 PowerShell 中不支持的问题,因为这些解决方案大多数时候都可以转换为 PowerShell 代码,但我找不到在没有自定义代码的情况下在 C# 中执行此操作的简单方法。
所以我认为您可能需要自己编写一些函数并使用Invoke-Expression 和引用类型(转换后的对象是 PSCustomObject)来帮助您。
概念证明(包含许多错误):
$json = @'
{
"foo": {"$ref": "#/bar"},
"bar": true
}
'@
$t = ConvertFrom-Json -InputObject $json
Write-Host "Before"
$t | Out-Host
function resolveReferences ($obj) {
#Loop through propeties
$obj.psobject.Properties | ForEach-Object {
#ref-values are PSCustomObjects with a $ref-property, so let's find the PSCustomObjects
if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject') {
#Verify it was a ref-value by checking for $ref-property
if ($_.Value.'$ref') {
#Convert value to powershell-path like $t.foo
$refpath = $_.Value.'$ref'.Replace("#/",'$t.').Replace("/",".")
#Execute generated powershell-path to get the referenced object and replace reference with the referenced object
$_.Value = (Invoke-Expression -Command $refpath)
}
}
}
}
resolveReferences -obj $t
Write-host "After"
$t | Out-Host
输出:
Before
foo bar
--- ---
@{$ref=#/bar} True
After
foo bar
--- ---
True True
您可以根据自己的需要进行扩展。前任。支持对象数组:
$json = @'
{
"foo": {"$ref": "#/bar"},
"fooarray": [
{"item": {"$ref": "#/bar"}},
{"item": {"$ref": "#/hello"}}
],
"test": [1,2,3],
"bar": true,
"hello": "world"
}
'@
$t = ConvertFrom-Json -InputObject $json
Write-Host "Before"
$t | Out-Host
function resolveReferences ($obj) {
$obj.psobject.Properties | ForEach-Object {
if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject') {
if ($_.Value.'$ref') {
$refpath = $_.Value.'$ref'.Replace("#/",'$t.').Replace("/",".")
$_.Value = (Invoke-Expression -Command $refpath)
}
} elseif ($_.TypeNameOfValue -eq 'System.Object[]') {
#If array, loop through objects (recursive search)
$_.Value | ForEach-Object { resolveReferences -obj $_ }
}
}
}
resolveReferences -obj $t
Write-host "After"
$t | Out-Host
输出:
#item properties in fooarray-objects are ref paths, it's just PS being to lazy to go deeper and show their values
Before
foo : @{$ref=#/bar}
fooarray : {@{item=}, @{item=}}
test : {1, 2, 3}
bar : True
hello : world
After
foo : True
fooarray : {@{item=True}, @{item=world}}
test : {1, 2, 3}
bar : True
hello : world
【讨论】: