2015-11-04 27 views
10

Próbuję przechodzić przez poniższy JSON w Powershell.Iterowanie przez plik JSON PowerShell

Bez konkretnego nazywania górnych znaczników (np. 17443, 17444), ponieważ nie znam ich z góry, nie mogę znaleźć sposobu na przechwycenie danych.

Chcę wyprowadzać tagi 3, 4 i 5 (tytuł, imię, nazwisko) dla wszystkich rekordów.

Jak to zrobić?

Każda pomoc mile widziane

{ 
    "17443":{ 
     "sid":"17443", 
     "nid":"7728", 
     "submitted":"1436175407", 
     "data":{ 
     "3":{ 
      "value":[ 
       "Mr" 
      ] 
     }, 
     "4":{ 
      "value":[ 
       "Jack" 
      ] 
     }, 
     "5":{ 
      "value":[ 
       "Cawles" 
      ] 
     } 
     }, 
     "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" 
       ] 
      } 
     } 
     } 
    } 
} 

mogę uzyskać dostęp do danych z poniższym kodzie, ale chcą uniknąć wprowadzenie w 17443, 17444 itd

 $data = ConvertFrom-Json $json 

    foreach ($i in $data.17443) 
    { 
     foreach ($t in $i.data.3) 
     { 
      write-host $t.value 
     } 
     foreach ($t in $i.data.4) 
     { 
      write-host $t.value 
     } 
     foreach ($t in $i.data.5) 
     { 
      write-host $t.value 
     } 

    } 
+2

Czy próbowałeś coś samemu lub czekasz, że ktoś realizuje to dla ciebie? – Tomalak

+0

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

+0

Zmieniłem moje pytanie z tym, więc jest bardziej pomocne – Omen9876

Odpowiedz

10

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]@{ .. } `
+0

dziękuję, to jest to, czego potrzebuję – Omen9876

-5

Oto proste rozwiązanie regex opartych . Zakładając, że $sRawJson zawiera wprowadzonych danych JSON:

$oRegex = [Regex]'(?:(?<="[345]":\{"value"\:\["))[^"]+' 
$cParts = $oRegex.Matches(($sRawJson -replace '\s')) | Select-Object -ExpandProperty "Value" 

łączenia części, aby uzyskać pełne nazwy:

for ($i = 0; $i -lt $cParts.Count/3; $i++) { $cParts[($i * 3)..($i * 3 + 2)] -join ' ' } 
+1

Nigdy nie chcesz dotknąć JSON za pomocą wyrażeń regularnych. – Tomalak

+0

Według ciebie może. Również downwotowanie odpowiedzi, która daje dokładnie to, o co proszą, jest po prostu destrukcyjne. –

+1

I downvote odpowiedzi, które robią nieprzydatne i niemądre rzeczy. Niezależnie od tego, czy są to przypadkowe wyjście, właściwa rzecz jest całkowicie poza tym punktem. Przekazuję również odpowiedzi, które sugerują, że XML lub HTML mogą być analizowane za pomocą wyrażeń regularnych, których nie mogą - z dokładnie tego samego powodu, dla którego JSON nie może być analizowany za pomocą wyrażeń regularnych. – Tomalak

Powiązane problemy