观察:
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 @()
[]