【问题标题】:JSONPath Wildcard equivalent in Powershell to select all array in ObjectPowershell中等效的JSONPath通配符以选择对象中的所有数组
【发布时间】:2022-10-31 03:52:12
【问题描述】:

我想从 Powershell 中的 JSON 文件中检索数据。我有这个 JSON 数据:

{
  "id": "abcxyz",
  "data": {
    "a": {
        "abc": "xyz"
    },
    "b": [
      {
        "bId": 2001,
        "bData": {
          "bAbc": [
            {
              "bAbcX": 123,
              "bAbcY": 456,
              "bAbcZ": "b1AbcZ0"
            },
            {
              "bAbcX": 312,
              "bAbcY": 654,
              "bAbcZ": "b1AbcZ1"
            }
          ],
          "bDef": [
            {
              "bDefX": 456,
              "bDefY": 654,
              "bDefZ": "b1DefZ0"
            },
            {
              "bDefX": 789,
              "bDefY": 987,
              "bDefZ": "b1DefZ1"
            }
          ]
        }
      },
      {
        "bId": 2002,
        "bData": {
          "bAbc": [
            {
              "bAbcX": 123,
              "bAbcY": 456,
              "bAbcZ": "b2AbcZ0"
            },
            {
              "bAbcX": 312,
              "bAbcY": 654,
              "bAbcZ": "b2AbcZ1"
            }
          ],
          "bDef": [
            {
              "bDefX": 456,
              "bDefY": 654,
              "bDefZ": "b2DefZ0"
            },
            {
              "bDefX": 789,
              "bDefY": 987,
              "bDefZ": "b2DefZ1"
            }
          ]
        }
      },
      {
        "bId": 2003,
        "bData": {
          "bAbc": [
            {
              "bAbcX": 123,
              "bAbcY": 456,
              "bAbcZ": "b3AbcZ0"
            },
            {
              "bAbcX": 312,
              "bAbcY": 654,
              "bAbcZ": "b3AbcZ1"
            }
          ],
          "bDef": [
            {
              "bDefX": 456,
              "bDefY": 654,
              "bDefZ": "b3DefZ0"
            },
            {
              "bDefX": 789,
              "bDefY": 987,
              "bDefZ": "b3DefZ1"
            }
          ]
        }
      }
    ]
  }
}

我想在 Powershell 中使用 JSONPath $.data.b[*].bData.bAbc[0].bAbcZ 检索数据。预期结果是:

[
  "b1AbcZ0",
  "b2AbcZ0",
  "b3AbcZ0"
]

JSONPath 在 https://jsonpath.com/ 中工作,这就是我尝试在 powershell 中检索它的方式:

$JSON = Get-Content ".\test.json" | Out-String | ConvertFrom-Json
$JSON.data.b[*].bData.bAbc[0].bAbcZ

但是当我在 Powershell 中尝试时,* 无效,这是输出:

+ $JSON.data.b[*].bData.bAbc[0].bAbcZ
+              ~
Array index expression is missing or not valid.

+ $JSON.data.b[*].bData.bAbc[0].bAbcZ
+               ~
You must provide a value expression following the '*' operator.

+ $JSON.data.b[*].bData.bAbc[0].bAbcZ
+               ~
Unexpected token ']' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : MissingArrayIndexExpression

我也尝试使用$JSON.data.b.bData.bAbc[0].bAbcZ,但它只检索第一个数据,即b1AbcZ0。 Powershell 对象中 JSON 通配符 (*) 的等价物是什么?

【问题讨论】:

  • PowerShell 作为 .NET 语言不支持开箱即用的 JSONPath。您可以使用 Newtonsoft JSON 模块 which does support JSONPath

标签: json powershell


【解决方案1】:

这是马虎,但应该做的伎俩。只需替换 $JSONData 中的 .json 文件路径即可。

$JSONData = Get-Content .DocumentsUntitled2.json |ConvertFrom-Json
$array = $JSONData.data.b.bdata.babc
$FinalArray = $JSONData.data.b.bdata | %{$_.bAbc[0].bAbcZ}
$FinalArray |Out-GridView

让我知道这是否有效!

【讨论】:

  • 好的。您可以精简到:$JSONData.data.b.bData.ForEach({ $_.bAbc[0].bAbcZ })
  • 顺便说一句:由于ConvertFrom-Json 无论如何都必须读取整个文件,因此您可以通过将-Raw 开关添加到Get-Content 调用来加快操作。
【解决方案2】:

您可以先使用类似于 JSONPath 的查询展开递归的 JSON 对象。然后您可以使用Where-Object 命令或.Where{} 方法按路径过滤JSON。

这是一个扁平化 JSON 的函数。它输出具有PathValue 属性的[PSCustomObject] 序列:

Function Expand-Json {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline)] $InputObject,
        [Parameter()] [string] $Path,
        [Parameter()] [string] $PathSeparator = '.',
        [Parameter()] [string] $IndexFormat = '<{0}>'
    )
    
    process {       
        if( $InputObject -is [Collections.IList] ) {
            # Iterate over array elements
            $i = 0
            foreach( $item in $InputObject ) {

                # Full path of current array item
                $itemPath = $Path + ($IndexFormat -f $i++)

                # Output current array item with path
                [PSCustomObject]@{ Path = $itemPath; Value = $item }

                if( $item -is [PSCustomObject] -or $item -is [Collections.IList] ) {
                    # Recurse into child container
                    Expand-Json -InputObject $item -Path $itemPath -PathSeparator $PathSeparator -IndexFormat $IndexFormat
                }
            }
        }
        elseif( $InputObject -is [PSCustomObject] ) {
            # Iterate over properties
            foreach( $prop in $InputObject.PSObject.Properties ) {

                # Full path of the current property
                $propertyPath = if( $Path ) { $Path, $prop.Name -join $PathSeparator } else { $prop.Name }

                # Output current property with path
                [PSCustomObject]@{ Path = $propertyPath; Value = $prop.Value }

                if( $prop.Value -is [PSCustomObject] -or $prop.Value -is [Collections.IList] ) {
                    # Recurse into child container
                    Expand-Json -InputObject $prop.Value -Path $propertyPath -PathSeparator $PathSeparator -IndexFormat $IndexFormat
                }
            }
        }
    }
}

使用示例:

$JSON = Get-Content ".	est.json" -Raw | ConvertFrom-Json

# Unroll the JSON
$flatJSON = $JSON | Expand-Json   

# Filter by path - this outputs an array
$filteredJSON = $flatJSON | Where-Object Path -like 'data.b<*>.bData.bAbc<0>.bAbcZ'

# Convert data back to JSON string
$filteredJSON.Value | ConvertTo-Json

输出:

[
  "b1AbcZ0",
  "b2AbcZ0",
  "b3AbcZ0"
]

笔记:

  • data.b&lt;*&gt;.bData.bAbc&lt;0&gt;.bAbcZ 的路径语法与 JSONPath 略有不同,以使其更易于与 PowerShell -like 运算符一起使用。
    • 没有根对象标记$,因为此字符对于PowerShell 字符串插值具有特殊意义。
    • 数组索引使用尖括号&lt;&gt; 表示,因为方括号[] 对于-like 运算符具有特殊含义(它们表示一系列字符,请参阅about Wildcards)。
  • 函数Expand-Json 概念清晰,但效率不高。通常,由于参数绑定开销,递归 PowerShell 函数往往相对较慢。如果性能是最重要的,有几种方法可以显着提高性能,例如。 G。通过使用类或内联 C#。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 2020-05-29
    相关资源
    最近更新 更多