仅当JSON属性存在时才排除它-Powershell

问题描述

我有两种不同的JSON,如果仅在Address(数组)下存在,我想从JSON对象中删除街道。我正在尝试在Powershell中执行此操作。我可以使脚本工作并删除街道,但是如果地址具有streets属性,我只想运行命令的排除行。

p.join()

第二个JSON-由于没有街道,所以不想为第二个JSON运行排除行

{
    "Customer": [{
        "id": "123"
    }],"address": [{
            "$type": "Home","name": "Houston","streets": [{
                "name": "Union","postalCode": "10"
            }]
        },{
            "$type": "Office","name": "Hawai","streets": [{
                "name": "Rock","postalCode": "11"
            }]
        }
    ]
}

Powershell脚本

{
    "Customer": [{
        "id": "123"
    }],"name": "Houston"
        },"name": "Hawai"
        }
    ]
}

解决方法

T-Me's helpful answer是最可靠的方法,因为它查找的是属性本身的存在,而不是非空的 values

如果您愿意假设缺少也意味着缺少属性本身,则可以采用以下捷径,效果更好:

$hasAtLeastOneStreet = 0 -ne
 (@((Get-Content Test.json -Raw | ConvertFrom-Json).address.streets) -ne $null).Count

.address.streets使用member enumeration提取所有streets的值,@(...)确保结果是一个数组,-ne $null过滤掉任何$null值,然后.Count对其元素进行计数。

注意:该表达式应该更简单:
$null -ne (Get-Content Test.json -Raw | ConvertFrom-Json).address.streets
但是由于 bug 当前无法执行-请参阅底部。

进行演示(输入字符串是JSON文档的压缩的单行版本):

'{"Customer":[{"id":"123"}],"address":[{"$type":"Home","name":"Houston","streets":[{"name":"Union","postalCode":"10"}]},{"$type":"Office","name":"Hawai","streets":[{"name":"Rock","postalCode":"11"}]}]}','{"Customer":[{"id":"123"}],"name":"Houston"},"name":"Hawai"}]}' | 
  foreach { 
    "has street values: " + 
      (0 -ne @(((ConvertFrom-Json $_).address.streets) -ne $null).Count)
  }

上面的结果表明,第一个JSON文档具有street值,而第二个JSON文档没有。

has street values: True
has street values: False

注意:您应该可以将测试表达式简化为以下内容,但是由于至少在PowerShell 7.0上出现了 bug ,因此无法正常工作:

# !! SHOULD worm,but as of PowerShell 7.0,DOESN'T,due to a bug relating
# to the presence of two or more [pscustomobject] instances in the address array:
$hasAtLeastOneStreet = 
  $null -ne (Get-Content Test.json -Raw | ConvertFrom-Json).address.streets

通常,缺少任何streets属性值都将导致$null,但是[pscustomobject]数组中存在两个或更多.address实例,则意外地返回了$null个值的数组

请参见GitHub issue #13752

,

如果您只想执行代码ifaddress具有member streets,则可以测试一下:

if (
    ($FileContent.address | Get-Member -MemberType NoteProperty -Name "streets") -ne $null
){
    $FileContent.address = $FileContent.address | Select-Object * -ExcludeProperty streets
}