如何在PowerShell中解析JSON响应

18

成功获取了JSON数据

$R= Invoke-WebRequest -Uri $url -Headers $headers -ContentType "application/json"   -Method Get -UseBasicParsing
$x = $R.Content | Out-String | ConvertFrom-Json 

现在我有一个这样的JSON文件:

{
  "id": 1000,
  "name_with_namespace": "myProjectName1",

},
{
  "id": 1001,
  "name_with_namespace": "myProjectName2",

},
{
  "id": 1002,
  "name_with_namespace": "myProjectName3",

}
现在我需要提取所有出现"name_with_namespace""id"的地方,其中"name_with_namespace" = "myProjectName.*"

如何一次完成呢?

我尝试过这个:

foreach ($name in $x.name_with_namespace) {
    if ( $name -match ".*myProjectName.*" ) {    
        write-host "$name - $x.id"               
    }   
}

但我得到了这个:

myProjectName1 1000 1001 1002
myProjectName2 1000 1001 1002
myProjectName3 1000 1001 1002

我理解问题在于 $x.id,如何获得正确的值而不是全部内容?

我的期望输出是:

myProjectName1 1000
myProjectName2 1001
myProjectName3 1002

你期望的输出是什么?迭代也考虑了子节点的迭代。这就是为什么你会在每个父节点处得到重复的ID。让我试一下。 - Ranadip Dutta
@RanadipDutta 我已经将它添加到主要问题中。 - ClaudioM
3个回答

14

当你定义循环时,不要深入到一个层级。只需迭代$x,然后在循环内部检查特定的属性。

foreach ($name in $x) {
    if ( $name.name_with_namespace -match ".*myProjectName.*" ) {    
        write-host "$($name.name_with_namespace) - $($name.id)"               
    }   
}

编辑:另外,你可以简化你的-match为只使用"myProjectName",它同样有效,而且很可能更快。


@ClaudioM:你也可以这样做。不过,我正在尝试将正确的JSON格式化TheMadTechnician。如果我漏掉了什么,请告诉我。 - Ranadip Dutta

2
"ConvertFrom-Json"在使用管道时有一些奇怪的行为。问题是,"ConvertFrom-Json"将JSON数组包装在一个数组中,然后将整个数组作为一个项目传递到管道中。在大多数情况下这样做没问题,但是如果最外层是一个JSON数组,那么整个数组会被作为单个对象传递到管道中。
比较一下:
PS> ConvertFrom-Json '[1, 2, 3]' | ForEach-Object  {": $_"}
: 1 2 3

PS> (ConvertFrom-Json '[1, 2, 3]') | ForEach-Object  {": $_"}
: 1
: 2
: 3

PS> $x = ConvertFrom-Json '[1, 2, 3]'
PS> $x | ForEach-Object  {": $_"}
: 1
: 2
: 3
PS> ,$x | ForEach-Object  {": $_"}
: 1 2 3

请注意,通过一元逗号运算符,我们可以复制问题。

这个问题已经在PowerShell Core 6中这里报告了。

尝试运行以下代码:

$j = @'
[
    {
        "id": 1000,
        "name_with_namespace": "myProjectName1"
    },
    {
        "id": 1001,
        "name_with_namespace": "myProjectName2"
    },
    {
        "id": 1002,
        "name_with_namespace": "myProjectName3"
    }
]
'@

($j | Out-String | ConvertFrom-Json) |
Where-Object name_with_namespace -match ".*myProjectName.*" |
ForEach-Object {
    "$($_.name_with_namespace) $($_.id)"
}

1

基本上,您已经获得了带有父节点的JSON,因此我不会涉及该部分。假设您已经拥有父节点,则可以直接执行以下操作:

$a=@"
{"ParentNode":[
    {"id":1000,"name_with_namespace":"myProjectName"},
    {"id":1001,"name_with_namespace":"myProjectName2"},
    {"id":1002,"name_with_namespace":"myProjectName3"}
]}
"@ 

($a | ConvertFrom-Json).ParentNode

输出:

id name_with_namespace
  -- -------------------
1000 myProjectName      
1001 myProjectName2     
1002 myProjectName3

您可以按照自己的方式进行解析,这一点没有问题。请确保您从restAPI接收到的json是结构良好的。使用点方法,您可以进入任何级别,并且还可以直接使用select-object选择它们。希望能对您有所帮助。

1
但是我没有“ParentNode”,我的JSON正好是我写的那样... - ClaudioM
请问您能否将$x的完整内容发送给我? - Ranadip Dutta
1
承认他的 JSON 示例有缺陷,但他的问题实际上与此部分无关,因为他展示了他能够通过属性名称从变量中获取值。他真正需要帮助的是能够按属性筛选对象并保留整个对象,而不仅仅是引用要过滤的属性并失去对象的其余部分。JSON 的事实在这种情况下是无关紧要的。就像高中数学中当他们给你带有额外无用信息的故事问题时,你必须确定所有相关的内容并进行处理。 - TheMadTechnician
@TheMadTechnician:明白了 :) 但还是感谢你的回答。 - Ranadip Dutta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接