PowerShell 3.0
W PowerShell 3.0 i wyższym można użyć ConvertFrom-Json
komandletu konwertować JSON ciąg do struktury danych PowerShell.
To wygodny i niefortunne w tym samym czasie - wygodny, ponieważ jest bardzo łatwy do spożywania JSON, niefortunne, ponieważ ConvertFrom-Json
daje PSCustomObjects i są trudne do iteracyjnego jako pary klucz-wartość.
W tym konkretnym JSON klucze wydają się być dynamiczne/nieznane z wyprzedzeniem, takie jak "17443"
lub "17444"
. Oznacza to, że potrzebujemy czegoś, co może przekształcić PSCustomObject
w listę klucz-wartość, którą może zrozumieć 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"}
}
}
Teraz możemy przemierzać wykres obiektu i stworzyć listę obiektów wyjściowych z Title
, FirstName
i 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
}
}
}
Output
Title FirstName LastName
----- --------- --------
Miss Charlotte Tann
Mr John Brokland
PowerShell 2.0/podejście alternatywna
Alternatywne podejście, które działa również w przypadku programu PowerShell 2.0 (który nie obsługuje niektórych z powyższych konstrukcji) wymagałoby użycia metody.NET JavaScriptSerializer class obsługiwać JSON:
Add-Type -AssemblyName System.Web.Extensions
$JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer
Teraz możemy zrobić bardzo podobną operację - nawet nieco prostsze jak wyżej, bo JavaScriptSerializer daje regularne Dictionaries, które są łatwe do iteracyjnego jako pary klucz-wartość poprzez GetEnumerator() metoda:
$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
}
}
}
wyjście jest takie samo:
Title FirstName LastName
----- --------- --------
Miss Charlotte Tann
Mr John Brokland
Jeśli czytać z pliku, należy użyć Get-Content -Raw -Encoding UTF-8
.
-Raw
ponieważ inaczej Get-Content
powraca szereg poszczególnych liniach i JavaScriptSerializer.DeserializeObject
nie może poradzić. Wydaje się, że ostatnie wersje Powershell mają ulepszoną konwersję typów dla argumentów funkcji .NET, więc może to nie spowodować błędu w systemie, ale jeśli tak (lub po prostu być bezpiecznym), użyj -Raw
.
- , ponieważ dobrze jest określić kodowanie pliku tekstowego podczas jego czytania, a najbardziej prawdopodobna wartość dla plików JSON to
UTF-8
.
Jeśli masz pliki JSON większe niż 4 MB, ustaw odpowiednio JavaScriptSerializer.MaxJsonLength
property.
Uwagi
ConvertFrom-Json()
daje niestandardowego obiektu PowerShell (PSCustomObject
) odzwierciedlającej dane w ciągu JSON.
- Można pętla chociaż właściwości niestandardowego obiektu z
Get-Member -type NoteProperty
- można uzyskać dostęp do właściwości obiektu dynamicznie przy użyciu składni
$object."$propName"
alternatywnie $object."$(some PS expression)"
.
- Można stworzyć własny obiekt i zainicjować go z wieloma właściwościami z
New-Object PSObject -Property @{...}
alternatywnie [PSCustomObject]@{ .. }
`
Czy próbowałeś coś samemu lub czekasz, że ktoś realizuje to dla ciebie? – Tomalak
Tak, mogę dostać się do danych przez specjalnie dodanie najlepszymi tagów, np foreach ($ i in $ data.17443) { foreach ($ t w $ i.data.3) { write-gospodarza $ t.value } foreach ($ t w $ i.data.4) { zapisu gospodarza $ t.value } foreach ($ t w $ i.data.5) { zapisu gospodarza $ t.value } } – Omen9876
Zmieniłem moje pytanie z tym, więc jest bardziej pomocne – Omen9876