【问题标题】:Handling JSON Reference with ConvertFrom-Json使用 ConvertFrom-Json 处理 JSON 引用
【发布时间】:2016-04-14 13:13:31
【问题描述】:

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

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

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

【问题讨论】:

    标签: json powershell


    【解决方案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
    

    【讨论】:

    • 伙计,就是这样!太感谢了。顺便问一下,MS 对 powershell 的这种功能 poc 的立场是什么?他们有功能推荐页面或类似的东西吗?
    • 是的,将建议发布到 Uservoice windowsserver.uservoice.com/forums/301869-powershell
    猜你喜欢
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 2017-07-21
    • 2016-04-26
    • 2013-07-14
    • 2015-03-20
    • 2015-05-25
    • 2019-08-24
    相关资源
    最近更新 更多