Ответ 1
PowerShell 3. 0+
В PowerShell 3.0 и выше (см. Определение установленной версии PowerShell) вы можете использовать командлет ConvertFrom-Json
для преобразования строки JSON в структуру данных PowerShell.
Это удобно и неудачно в то же время - удобно, потому что очень легко использовать JSON, к сожалению, потому что ConvertFrom-Json
предоставляет вам PSCustomObjects, и их трудно перебирать как пары ключ-значение.
В этом конкретном JSON ключи кажутся динамическими/неизвестными заранее, как "17443"
или "17444"
. Это означает, что нам нужно что-то, что может превратить PSCustomObject
в список значений ключа, который может понять foreach
.
# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMembers {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[PSCustomObject]$obj
)
$obj | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]@{Key = $key; Value = $obj."$key"}
}
}
Теперь мы можем пройти по графу объектов и создать список выходных объектов с помощью Title
, FirstName
и LastName
$json = '{"17443": {"17444": {"sid": "17444","nid": "7728","submitted": "1436891400","data": {"3": {"value": ["Miss"]},"4": {"value": ["Charlotte"]},"5": {"value": ["Tann"]}}},"17445": {"sid": "17445","nid": "7728","submitted": "1437142325","data": {"3": {"value": ["Mr"]},"4": {"value": ["John"]},"5": {"value": ["Brokland"]}}},"sid": "17443","nid": "7728","submitted": "1436175407","data": {"3": {"value": ["Mr"]},"4": {"value": ["Jack"]},"5": {"value": ["Cawles"]}}}}'
$json | ConvertFrom-Json | Get-ObjectMembers | foreach {
$_.Value | Get-ObjectMembers | where Key -match "^\d+$" | foreach {
[PSCustomObject]@{
Title = $_.value.data."3".value | select -First 1
FirstName = $_.Value.data."4".value | select -First 1
LastName = $_.Value.data."5".value | select -First 1
}
}
}
Выход
Title FirstName LastName ----- --------- -------- Miss Charlotte Tann Mr John Brokland
PowerShell 2.0/Альтернативный подход
Альтернативный подход, который также работает для PowerShell 2.0 (который не поддерживает некоторые из приведенных выше конструкций), предполагает использование класса.NET JavaScriptSerializer для обработки JSON:
Add-Type -AssemblyName System.Web.Extensions
$JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer
Теперь мы можем сделать очень похожую операцию - даже немного проще, чем выше, потому что JavaScriptSerializer предоставляет вам обычные словари, которые легко перебирать в виде пар ключ-значение с помощью метода GetEnumerator()
:
$json = '{"17443": {"17444": {"sid": "17444","nid": "7728","submitted": "1436891400","data": {"3": {"value": ["Miss"]},"4": {"value": ["Charlotte"]},"5": {"value": ["Tann"]}}},"17445": {"sid": "17445","nid": "7728","submitted": "1437142325","data": {"3": {"value": ["Mr"]},"4": {"value": ["John"]},"5": {"value": ["Brokland"]}}},"sid": "17443","nid": "7728","submitted": "1436175407","data": {"3": {"value": ["Mr"]},"4": {"value": ["Jack"]},"5": {"value": ["Cawles"]}}}}'
$data = $JS.DeserializeObject($json)
$data.GetEnumerator() | foreach {
$_.Value.GetEnumerator() | where { $_.Key -match "^\d+$" } | foreach {
New-Object PSObject -Property @{
Title = $_.Value.data."3".value | select -First 1
FirstName = $_.Value.data."4".value | select -First 1
LastName = $_.Value.data."5".value | select -First 1
}
}
}
Вывод такой же:
Title FirstName LastName ----- --------- -------- Miss Charlotte Tann Mr John Brokland
Если размер JSON превышает 4 МБ, соответственно установите свойство JavaScriptSerializer.MaxJsonLength
.
При чтении JSON из файлов
Если вы читаете из файла, используйте Get-Content -Raw -Encoding UTF-8
.
-
-Raw
потому что иначеGet-Content
возвращает массив отдельных строк, аJavaScriptSerializer.DeserializeObject
не может это обработать. В последних версиях Powershell, по-видимому, улучшено преобразование типов для аргументов функций .NET, поэтому в вашей системе это может не привести к ошибкам, но если это произойдет (или просто будет безопасно), используйте-Raw
. -
-Encoding
потому что при чтении целесообразно указывать кодировку текстового файла, аUTF-8
является наиболее вероятным значением для файлов JSON.
Заметки
-
ConvertFrom-Json()
предоставляет пользовательский объект PowerShell (PSCustomObject
), который отражает данные в строке JSON. - Вы можете зациклить свойства пользовательского объекта с помощью
Get-Member -type NoteProperty
- Вы можете получить динамический доступ к свойствам объекта, используя синтаксис
$object."$propName"
, альтернативно$object."$(some PS expression)"
. - Вы можете создать свой собственный объект и инициализировать его с помощью
New-Object PSObject -Property @{...}
свойств с помощьюNew-Object PSObject -Property @{...}
, альтернативно[PSCustomObject]@{.. }
'