如何使用ConvertTo-Json将PowerShell数组转换为JSON格式?

9

请注意:

C:\> [array]@(1,2) | ConvertTo-Json
[
    1,
    2
]
C:\> [array]@(1) | ConvertTo-Json
1
C:\> [array]@() | ConvertTo-Json
C:\>

我希望从最后两种情况中分别得到[1]和[]。

因此,如果我想使用标准的ConvertTo-Json方法,即使数组只包含1个或0个元素,我如何可靠地执行它?

请注意,当数组是转换为json的复杂对象的一部分时,后处理结果是不可行的。

编辑1

C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.17763.592
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.592
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


C:\> [array]@(1) | ConvertTo-Json -AsArray
ConvertTo-Json : A parameter cannot be found that matches parameter name 'AsArray'.
At line:1 char:30
+ [array]@(1) | ConvertTo-Json -AsArray
+                              ~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [ConvertTo-Json], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.ConvertToJsonCommand

C:\>

2
使用 -AsArray 开关。 - AdminOfThings
不错的指针,@AdminOfThings,但值得注意的是-AsArray仅在PowerShell _Core_中受支持;还要注意它与空数组的预期行为不同:例如,ConvertTo-Json -AsArray @() -Compress返回[[]] - mklement0
2个回答

7

PowerShell Core(v6+)提供了方便的-AsArray开关,详见底部部分。


如果$val为空数组、标量或数组,则通过管道将, @($val)发送给ConvertTo-Json以确保它被序列化为一个数组

if (-not $IsCoreCLR) {  # Workaround for Windows PowerShell
 # Only needed once per session.
 Remove-TypeData -ErrorAction Ignore System.Array
}

# Send an empty array, a single object, and an array...
@(), 1, (1, 2) | ForEach-Object { 
  # ... and ensure that each input ($_) serializes as a JSON *array*.
  , @($_) | ConvertTo-Json 
}

注意:
  • 需要使用Windows PowerShell解决方法,请参见此答案

  • ,,数组构造运算符在此处以其一元形式使用,提供了辅助的单元素数组,以便将数组作为整体(作为一个对象)通过管道发送;默认情况下,将数组(可枚举)发送到管道会一个一个地发送其元素;请注意,这是管道行为的基本特性,与所涉及的cmdlet无关。

  • @(...),“数组保证”运算符(数组子表达式运算符)确保 $_ 是一个数组,也就是说,它用一个数组包装操作数,除非它已经是一个数组(松散说); 这是为了覆盖$_仅包含单个对象(标量; 在本例中为1)的情况。

  • 一个常规警告: ConvertTo-Json默认情况下静默地将其序列化深度限制为2,这导致更深层嵌套的输入数据丢失; 根据需要使用-Depth参数。

  • 上述内容产生以下结果-请注意每个输入都被序列化为一个数组:
    []
    [
      1
    ]
    [
      1,
      2
    ]
    

    或者,您可以将输入作为参数传递给ConvertTo-Json, 使用@($val)

    # Same output as above.
    @(), 1, (1,2) | ForEach-Object { ConvertTo-Json @($_) }
    

    一个位置参数会隐式绑定到 -InputObject 参数,它不会枚举其参数,因此数组将按原样绑定。 因此,在这种情况下,您只需要使用 "array guarantor" @()(而不是带有的包装器数组)。
    PowerShell Core现在提供了一个-AsArray开关,该开关直接确保输入被序列化为数组,即使只有一个输入对象:
    PS> 1 | ConvertTo-Json -AsArray
    [
      1
    ]
    

    然而,由于空数组通过管道时不会传递任何数据,因此如果输入是空数组,则仍需要一个包装器数组,如果使用 -AsArray,则会出现问题。

    # Note:
    #   @() | ConvertTo-Json -AsArray
    # would result in NO output.
    # Use `, ` to wrap the empty array to ensure it gets sent through
    # the pipeline and do NOT use -AsArray
    PS> , @() | ConvertTo-Json -Compress
    
    []
    

    或者,再次将空数组作为参数传递:

    PS> ConvertTo-Json @() -Compress # Do NOT use -AsArray
    
    []
    

    问题在于,-AsArray 无条件地将其输入内容包装成 JSON 数组,因此已经是数组的内容会被再次包装:

    PS> ConvertTo-Json -AsArray @() -Compress
    
    [[]]  # *nested* empty arrays
    

    -AsArray并不像@(...)那样作为数组的“保证人”,这个问题在GitHub issue中讨论。


    [1] 如果操作数是一个标量(单一对象),它将被封装在一个单元素的[object[]]中;如果操作数已经是一个数组或可枚举的,那么这些元素会被枚举并捕获到一个新的[object[]]数组中。


    7

    终于,-InputObject 也有了用处:

    convertto-json -InputObject @(1)
    [
      1
    ]
    
    convertto-json -InputObject @() 
    []
    

    2
    是的,绑定到“-InputObject”会防止管道默认执行的数组枚举;请注意,在这种情况下,“-InputObject”绑定为位置性,因此您不需要指定“-InputObject”(这就是我在答案中省略它的原因);例如,“ConvertTo-Json @()”将起作用。 - mklement0

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