Как преобразовать массив powershell в json с помощью ConvertTo-Json? - PullRequest
2 голосов
/ 30 октября 2019

Наблюдение:

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 ]

3 голосов
/ 30 октября 2019

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 объясняется в этом ответе .

  • ,, оператор массива , оператор , используется здесь в его унарной форме, чтобы обеспечить вспомогательный одноэлементный массив wrapper в следующем порядке: отправить массив целиком (как один объект) по конвейеру; по умолчанию отправка массива (перечислимого) в конвейер отправляет его элементы один за другим ;обратите внимание, что это фундаментальное конвейерное поведение, независимо от используемых командлетов.

  • @(...), «массив-гарант» оператор (оператор подвыражения массива), гарантирует , что $_ является массивом , то есть он оборачивает операнд в массив, если он уже не равен единице (свободно говоря [1] );это необходимо для случая $_, содержащего только один один объект (в данном случае скаляр; 1).

  • Общие положенияпредостережение : ConvertTo-Json тихо ограничивает глубину сериализации до 2 по умолчанию , что приводит к тихой потере данных при более глубоко вложенном вводе ;При необходимости используйте параметр -Depth.

Из приведенного выше вытекает следующее:обратите внимание, как каждый вход был сериализован в виде массива:

[]
[
  1
]
[
  1,
  2
]

В качестве альтернативы вы можете передавать входные данные как аргументы в ConvertTo-Json с @($val):

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

Позиционный аргумент неявно связывается с параметром -InputObject, который не перечисляет свой аргумент и поэтому связывает массивы как есть. Следовательно, в этом случае вам нужен только «массив-гарант» @() (не также массив-оболочка с , ).


PowerShell Core теперь предлагает-AsArray switch , который напрямую обеспечивает сериализацию входных данных в виде массива, даже если существует только одиночный входной объект:

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 .


[1] Если операндом является скаляр (один объект), он заключен в один элемент [object[]];если операнд уже является массивом или перечислимым, элементы перечисляются и записываются в массив new [object[]].

1 голос
/ 30 октября 2019

Наконец, использование для -InputObject:

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

convertto-json -InputObject @() 
[]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...