PowerShell处理JSON数组时保留结构问题求助
保留数组结构并修正值格式的解决建议
问题概述
需要处理嵌套对象中的特定节点:当节点值为数组时,保留数组结构,并给数组中符合^\[\w+规则的元素添加前缀[。当前处理会将数组拼接为字符串,导致结构丢失,不符合预期输出。
现有代码
Get-Node 遍历函数
function Get-Node { [CmdletBinding()][OutputType([Object[]])] param( [ScriptBlock]$Where, [AllowNull()] [Parameter(ValueFromPipeLine = $True, Mandatory = $True)]$InputObject, [Int]$Depth = 90 ) process { if ($_ -isnot [String] -and $Depth -gt 0) { if ($_ -is [Collections.IDictionary]) { if (& $Where) { $_ } $_.get_Values() | Get-Node -Where $Where -Depth ($Depth - 1) } elseif ($_ -is [Collections.IEnumerable] -and $_ -isnot [String]) { # 排除字符串,仅处理数组/集合类型 if (& $Where) { $_ } # 递归处理每个元素,保留原数组结构 for ($i = 0; $i -lt $_.get_Count(); $i++) { $_[$i] = $_[$i] | Get-Node -Where $Where -Depth ($Depth - 1) } $_ # 返回处理后的数组 } elseif ($Nodes = $_.PSObject.Properties.Where{ $_.MemberType -eq 'NoteProperty' }) { $Nodes.ForEach{ if (& $Where) { $_ } # 递归处理属性值,保留数组结构 $_.Value = $_.Value | Get-Node -Where $Where -Depth ($Depth - 1) } } } } }
原调用代码
if ($content.properties.policyRule -ne $null){ foreach ($rule in $policyRule){ $Node = $content.properties | Get-Node -Where {$_.name -eq $rule -and $_.value -Match "^\[\w+"} $Node | ForEach-Object { $_.Value = '[' + $_.Value } } }
当前输出 vs 期望输出
当前输出(数组被拼接为字符串)
"notIn": "[[concat(subscription().id,'/')] [subscription().id] /"
期望输出(保留数组结构,每个元素添加前缀)
"notIn": ["[[concat(subscription().id,'/')]", "[[subscription().id]", "/"]
修正方案
1. 调整Get-Node函数,确保数组结构不丢失
修改原函数中对IEnumerable类型的处理逻辑:
- 增加排除
String类型的判断(字符串也实现了IEnumerable,需避免误处理) - 处理数组元素时,直接修改原数组的对应位置,而非仅管道输出单个元素
- 处理完数组后返回整个数组,保证结构不丢失
- 处理NoteProperty的Value时,直接赋值处理后的结果,确保数组结构被保留
2. 修改调用代码,针对数组元素逐个处理
将原调用代码中的字符串拼接逻辑,改为分类型处理:如果是数组则遍历每个元素,给符合规则的元素添加前缀;如果是单个值则直接处理。同时调整Where条件,避免因数组整体匹配导致的误判。
修正后的调用代码:
if ($content.properties.policyRule -ne $null){ foreach ($rule in $policyRule){ $Node = $content.properties | Get-Node -Where {$_.name -eq $rule} $Node | ForEach-Object { if ($_.Value -is [Collections.IEnumerable] -and $_.Value -isnot [String]) { # 处理数组类型:逐个检查元素,添加前缀 $updatedArray = $_.Value | ForEach-Object { if ($_ -Match "^\[\w+") { '[' + $_ } else { $_ } } $_.Value = $updatedArray } else { # 处理单个值 if ($_.Value -Match "^\[\w+") { $_.Value = '[' + $_.Value } } } } }
关键说明
- 移除原Where条件中的
$_.value -Match "^\[\w+",改为在处理阶段判断单个元素是否符合规则,避免数组整体匹配导致的逻辑错误 - 处理数组时通过
ForEach-Object遍历,仅给符合^\[\w+规则的元素添加前缀[ - 保留非数组类型值的原有处理逻辑,保证代码兼容性
内容的提问来源于stack exchange,提问作者Raymondo
相关产品推荐
相关产品推荐

