如何使用 ConvertTo-Json 将 powershell 数组转换为 json?

mar*_*ark 5 powershell json

观察:

C:\> [array]@(1,2) | ConvertTo-Json
[
    1,
    2
]
C:\> [array]@(1) | ConvertTo-Json
1
C:\> [array]@() | ConvertTo-Json
C:\>
Run Code Online (Sandbox Code Playgroud)

(我希望分别来自最后两个案例的 [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:\>
Run Code Online (Sandbox Code Playgroud)

js2*_*010 7

最后,-InputObject 的用途:

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

convertto-json -InputObject @() 
[]
Run Code Online (Sandbox Code Playgroud)

  • 是的,绑定到“-InputObject”会阻止管道默认执行的数组枚举;请注意,在这种情况下,“-InputObject”会绑定_positionally_,因此您无需指定“-InputObject”(这就是我在答案中省略的原因);例如,“ConvertTo-Json @()”就可以了。 (2认同)

mkl*_*nt0 5

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 
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 此答案中解释了对 Windows PowerShell 解决方法的需求。

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

  • @(...)“数组保证”运算符(数组子表达式运算符),确保$_是一个数组,也就是说,它将操作数包装在一个数组中,除非它已经是一个(松散地说[1]);这对于涵盖$_仅包含单个对象(标量;1在这种情况下)的情况是必要的。

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

以上产生以下结果 - 请注意每个输入是如何序列化为数组的:

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 
}
Run Code Online (Sandbox Code Playgroud)

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

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

位置参数隐式绑定到-InputObject参数,该参数枚举其参数,因此按原样绑定数组。因此,@()在这种情况下,您只需要“数组保证器” (也不是带有 的包装器数组)。


PowerShell的核心现在提供一个-AsArray开关,它直接保证输入被序列作为阵列,即使只有一个单一的输入对象:

PS> 1 | ConvertTo-Json -AsArray
[
  1
]
Run Code Online (Sandbox Code Playgroud)

但是,鉴于空数组导致没有数据通过管道发送,如果输入是空数组,则-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

[]
Run Code Online (Sandbox Code Playgroud)

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

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

[]
Run Code Online (Sandbox Code Playgroud)

问题是-AsArray 无条件地将它的输入包装在一个 JSON 数组中,这样已经是一个数组的东西被包装

PS> ConvertTo-Json -AsArray @() -Compress

[[]]  # *nested* empty arrays
Run Code Online (Sandbox Code Playgroud)

-AsArray并不像此 GitHub 问题中讨论的那样充当数组“担保人” 。@(...)


[1] 如果操作数是标量(单个对象),则包裹在单个元素中[object[]];如果操作数已经是一个数组或者是一个可枚举的,元素被枚举并捕获到一个 [object[]]数组中。