如何使用ConvertToJson将powershell数组转换为json



观察:

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:>

注意:

  • 下面的答案讨论了通过管道向ConvertTo-Json提供输入,以及使用单个元素数组作为输入的陷阱,以及解决方法。

    • 正如js2010的有用答案所示,如果您将这样一个数组作为参数(例如ConvertTo-Json (@1)(传递,则最容易避免这个陷阱,也将在下面解释。

    • 对于管道输入,PowerShell(Core(7+现在提供了方便的-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](;这对于涵盖$_仅包含单个对象(标量;在这种情况下为1(的情况是必要的。

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

    • 这篇SO文章讨论了这个问题。

    • GiHub问题#8393要求改变危险的默认行为;虽然这并没有发生,但PowerShell 7+现在至少省略了警告,然后发生截断。

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

[]
[
1
]
[
1,
2
]

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

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

位置参数隐式绑定到-InputObject参数,该参数不枚举其参数,因此按原样绑定数组。因此,您只需要";阵列保证器";在这种情况下为CCD_ 18(不是具有CCD_ 19的包装器阵列(。


PowerShellCore现在提供了-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

CCD_ 23不充当数组";担保人;CCD_ 24的方式在GitHub第10952期中进行了讨论。


[1]如果操作数是标量(单个对象(,则将其封装在单个元素[object[]]中;如果操作数已经是一个数组或是可枚举的,则会在[object[]]数组中枚举和捕获元素

最后,使用-InputObject:

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

最新更新