我需要使用 ps 从 JSON 文件中提取一些信息。 JSON 具有嵌套的
components
数组,其中还可以包含 components
数组。
{
"name": "app",
"components": [
{
"component_name": "comp1",
"component_packages": [
"comp1_package1",
"comp1_package2"
],
"project_id": "1234",
"file_path": "requirements_file",
"ref": "%%VERSION%%",
"components": [
{
"component_name": "comp1.1",
"component_packages": [
"comp1.1_package1"
],
"project_id": "2345",
"file_path": "requirements_file",
"ref": "%%VERSION%%",
"components": [
{
"component_name": "comp1.1.1",
"component_packages": [
"comp1.1.1_package1"
],
"project_id": "3456",
"file_path": "requirements_file",
"ref": "%%VERSION%%",
"components": []
}]
},
{
"component_name": "comp1.2",
"component_packages": [
"comp1.2_package1"
],
"project_id": "4567",
"file_path": "requirements_file",
"ref": "%%VERSION%%",
"components": []
}
]
},
{
"component_name": "comp2",
"component_packages": [
"comp2_package1",
"comp2_package2"
],
"project_id": "5678",
"file_path": "requirements_file",
"ref": "%%VERSION%%",
"components": [
{
"component_name": "comp2.1",
"component_packages": [
"comp2.1_package1"
],
"project_id": "6789",
"file_path": "requirements_file",
"ref": "%%VERSION%%",
"components": []
}
]
}
]
}
对于
component
内的每个 components
,我需要执行一个脚本来收集更多信息,但我很难对所有元素一一进行迭代。
我开始将 JSON 转换为 psobject (
Get-Content -Raw "$json_path" | ConvertFrom-Json
)
我不想修复 JSON 的深度。所以脚本应该具有适应性。
我尝试使用
while
循环
$comp = $object.components
while ( $comp -ne "" ) {
$comp | ForEach-Object {
# to something
}
}
但是这样不合适,因为即使我覆盖
$comp
,脚本也会忘记一些条目。
只需使用一个函数并递归调用它
(注意:这可能不是最有效的方法)
$JsonObj = $Json | ConvertFrom-Json
function Drill-Json {
[CmdletBinding()]
param (
[Parameter(
Mandatory,
Position = 0,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ValueFromRemainingArguments
)]
[array]$JsonComponent
)
$JsonComponent | ForEach-Object {
<#
DO STUFF
#>
# $_.component_name
if (($_.components.count)) {
Drill-Json -JsonComponent $_.components
}
}
}
Drill-Json -JsonComponent $JsonObj.components
对象图(独立于源,如Json、Yaml或PowerShell本身)可能确实会变得相当复杂。这就是为什么我开始编写 ObjectGraphTools 模块,它可以帮助您探索相关对象,迭代节点,或者简单地查明特定节点(并更改其值)。
Install-Module -Name ObjectGraphTools
$Object = $Json | ConvertFrom-Json # Where $Json holds the json string of your question
示例$Object.components
节点下的所有节点:
$Object | Get-Node Components | Get-ChildNode
Path Name Depth Value
---- ---- ----- -----
components[0] 0 2 @{component_name=comp1; component_packages=System.Object…
components[1] 1 2 @{component_name=comp2; component_packages=System.Object…
递归搜索所有
Components
节点(您的具体问题):
$Object | Get-Node | Get-ChildNode -Recurse Components
Path Name Depth Value
---- ---- ----- -----
components components 1 {@{component_…
components[0].components components 3 {@{component_…
components[0].components[0].components components 5 {@{component_…
components[0].components[0].components[0].components components 7 {}
components[0].components[1].components components 5 {}
components[1].components components 3 {@{component_…
components[1].components[0].components components 5 {}
但事情可能还没有结束。要获取
$Object.components
节点下的叶节点的完整列表:
$Object | Get-Node Components | Get-ChildNode -Leaf -Recurse
Path Name Depth Value
---- ---- ----- -----
...
components[0].components[0].ref ref 5 %%VERSION%%
components[0].components[0].components[0].component_name component_name 7 comp1.1.1
components[0].components[0].components[0].component_packages[0] 0 8 comp1.1.1_package1
components[0].components[0].components[0].project_id project_id 7 3456
components[0].components[0].components[0].file_path file_path 7 requirements_file
components[0].components[0].components[0].ref ref 7 %%VERSION%%
components[0].components[1].component_name component_name 5 comp1.2
components[0].components[1].component_packages[0] 0 6 comp1.2_package1
components[0].components[1].project_id project_id 5 4567
components[0].components[1].file_path file_path 5 requirements_file
components[0].components[1].ref ref 5 %%VERSION%%
components[1].component_name component_name
...
您可以使用特定路径属性来定位任何特定节点,例如:
$Object | Get-Node components[0].components[0].components[0].project_id
Path Name Depth Value
---- ---- ----- -----
components[0].components[0].components[0].project_id project_id 7 3456
或使用Member-Access 枚举
:
$Object | Get-Node components.components.components.project_id
Path Name Depth Value
---- ---- ----- -----
components[0].components[0].components[0].project_id project_id 7 3456
您可能要去的地方是获取具有特定子节点的
components
之一,并更改另一个子节点的值。
该语法还支持通配符,并具有一些“扩展点表示法 (Xdn)”运算符,可让您自由地定位深层节点。例如:
$Object | Get-Node ~project_id=3456
Path Name Depth Value
---- ---- ----- -----
components[0].components[0].components[0].project_id project_id 7 3456
例如更改 ref
为
component
的
product_id
的 3456
值,例如:($Object | Get-Node ~project_id=3456..ref).Value = '1.2.3.4'
(确认结果:$Object | ConvertTo-Json -Depth 9
)
说明:
~project_id
的任何后代节点
=3456
过滤结果节点,其中值等于 ..
选择父级ref
选择名为 project_id节点的兄弟节点) 节点的
Value
属性是对对象图中相关值的引用,因此可能用于修改原始对象。