使用ConvertFrom-Json处理JSON引用

时间:2016-04-14 13:13:31

标签: json powershell

默认情况下,PowerShell的ConvertFrom-Json cmdlet似乎不处理JSON文档中的引用。

{
    "foo": {"$ref": "#/bar"},
    "bar": true
}

我真的不知道这个JSON规范的官方状态(请参阅herehere),但有没有办法在PowerShell中管理这样的事情?

1 个答案:

答案 0 :(得分:1)

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