Отправка массива объектов в API в Powershell

Мне нужно взаимодействовать с API, который, помимо прочих параметров, ожидает массив объектов. Пример:

{
    "fields":  {
        "somefield": "somevalue",
        "someobject": {
            "name": "foobar"
        },
        "versions":  [
            {
                "name": "1.0"
            }
        ]
    }
}

С помощью этого ответа я попробовал два разные способы справиться с этим. Я объединил их в один пример кода:

$versionName = New-Object -TypeName PSObject
$versionName | Add-Member -Name "name" -MemberType NoteProperty -Value "1.0"

$versionName2 = @{}
$versionName2.name = "1.0"

$postIssueBody = @{}
$postIssueBody.fields = @{}
$postIssueBody.fields.somefield = "somevalue"
$postIssueBody.fields.someobject = @{}
$postIssueBody.fields.someobject.name = "foobar"
$postIssueBody.fields.version = @($versionName)
$postIssueBody.fields.version2 = @()
$postIssueBody.fields.version2 += [pscustomobject]$versionName2

$postIssueRequestJson = $postIssueBody | ConvertTo-Json

$postIssueRequestJson

Это приводит к следующему результату:

{
    "fields":  {
        "somefield": "somevalue",
        "someobject": {
            "name": "foobar"
        },
        "version":  [
            "@{name=1.0}"
        ],
        "version2":  [
            "@{name=1.0}"
        ]
    }
}

Как видите, это не будет работать как действительный JSON. Как лучше всего обработать это назначение, чтобы имена версий правильно формировались после прохождения ConvertTo-Json?


person Ellesedil    schedule 15.08.2014    source источник


Ответы (2)


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

$postIssueRequestJson = $postIssueBody | ConvertTo-Json -Depth 3

И теперь у нас есть правильно сформированный JSON.

{
    "fields":  {
        "somefields":  "somevalue",
        "someobject":  {
            "name":  "foobar"
        },
        "versions":  [
            {
                "name":  "1.0"
            }
        ]
    }
}
person Ellesedil    schedule 16.08.2014

Хорошо, думаю, я понял. Итак, вам нужна строка, начинающаяся с "versions": и за которой следует массив объектов, да? Итак, начнем с пустого массива.

$Array = @()

Затем мы можем создавать объекты и добавлять их в массив:

$Array += [PSCustomObject]@{"Name1"="1.0.0"}
$Array += [PSCustomObject]@{"Name2"="3.10.0"}

Теперь у нас есть массив PowerShell с PSCustomObjects в нем. Мы можем передать это в ConvertTo-JSON, и он выведет:

[
    {
        "Name1":  "1.0.0"
    },
    {
        "Name2":  "3.10.0"
    }
]

Какой массив объектов вы хотели. Если вы хотите, чтобы объект имел это значение, вы можете просто создать другой объект для этого:

$Versions = [PSCustomObject]@{'versions'=$Array}

Затем вы можете преобразовать это в JSON, если хотите, и получить:

{
    "versions":  [
                     {
                         "Name1":  "1.0.0"
                     },
                     {
                         "Name2":  "3.10.0"
                     }
                 ]
}

Это то, что вы искали, верно? Или, если вы действительно хотите это в одной строке:

PS C:\> ($Versions|convertto-json).split() -join ""

{"versions":[{"Name1":"1.0.0"},{"Name2":"3.10.0"}]}

Чтобы быть отформатированным точно так же, как ваш первый пример, нам нужно было бы избавиться от { }, окружающих этот результат, я полагаю, вы можете сделать это с помощью Trim() как такового:

PS C:\> ($Versions|convertto-json).trim("{}").split() -join ""

"versions":[{"Name1":"1.0.0"},{"Name2":"3.10.0"}]

Редактировать: Хорошо, поэтому вам просто нужно добавить объекты в качестве значений свойств других объектов по мере необходимости, так же, как я сделал для установки массива в качестве значения в объекте в моем примере.

Я думаю, что самый простой способ понять, что нужно сделать, - это взять ваш пример (без последней запятой, так как это приводит к ошибкам), передать его в ConvertFrom-JSON и присвоить ему переменную. Затем вы можете увидеть, как это формируется в Powersell. Как только я это сделаю (я назвал свою переменную $JSON), я вижу, что $JSON имеет 1 NoteProperty из «полей». Это свойство NoteProperty имеет 3 свойства NoteProperties: «somefield», «someobject» и «versions». Когда я делаю $JSON.fields|Get-Member, я узнаю о них больше.

somefield — это просто строка. С этим будет достаточно легко справиться.

someobject — это PSCustomObject, в основном HashTable, где name=foobar.

version просто показывает, что это System.Object, поэтому я сделаю $JSON.fields.versions.GetType(), и он покажет, что basetpe — это System.Array. После просмотра версий он выглядит как массив с 1 объектом в нем, и этот объект имеет одно свойство note, которое является строкой (как и первый объект, который у нас был).

Итак, есть два способа сделать это. Вы можете либо попытаться создать свои объекты и массивы в режиме реального времени, либо сделать их заранее, начиная с самого глубокого вложенного слоя и продвигаясь вверх. Я покажу вам позже.

$name = [PSCustomObject]@{'name'='1.0'}
$versions=@($name)
$Someobject = [PSCustomObject]@{'name'='foobar'}
$Fields = [PSCustomObject]@{
        'somefields'='somevalue'
        'someobject'=$someobject
        'versions'=$versions}
$NewJSON = [PSCustomObject]@{'Fields'=$fields}
$NewJSON | ConvertTo-Json
person TheMadTechnician    schedule 15.08.2014
comment
Однострочный был только потому, что я использовал блочные кавычки и вместо блоков кода. На самом деле мне все равно, потому что я не буду выводить JSON перед отправкой его в API. Хотя я могу заставить ваш пример работать, как только я добавлю его к объекту, который я создаю для всего тела, он вернется к поведению, которое я показал в своем вопросе. Я отредактировал вопрос, чтобы более четко объяснить, что мне нужно. - person Ellesedil; 16.08.2014
comment
Похоже, это не работает :( Если я буквально скопирую и вставлю ваш код и запущу его, все будет выглядеть нормально, за исключением этого: "versions": [ "@{name=1.0}" ] так что похоже, что мы все еще сталкиваемся с той же проблемой. Хороший призыв написать JSON и с помощью ConvertFrom-Json Признаться, эта идея пришла мне в голову во время обеда, но я не смог ее опробовать. - person Ellesedil; 16.08.2014
comment
Хорошо, это странно. Если вы добавите Write-Output $Fields | ConvertTo-Json, вывод будет отформатирован правильно. Как только вы включите $Fields в $NewJSON и преобразуете его, он вернется обратно к "@{name=1.0}". Это не имеет никакого смысла... возможно, это ошибка в Powershell? - person Ellesedil; 16.08.2014
comment
Нашел. ConvertTo-Json имеет переключатель под названием Depth. Вам нужно включить его на $NewJSON. По умолчанию глубина установлена ​​на 2. Итак, нам действительно нужно $NewJSON | ConvertTo-Json -Depth 3. На самом деле, это единственная корректировка, которую мне нужно сделать, даже с моим исходным кодом. - person Ellesedil; 16.08.2014