2015-11-04 138 views
10

我想通過Powershell中的下面的JSON循環。通過JSON文件迭代PowerShell

沒有特別命名頂部標籤(例如17443,17444),因爲我事先不知道它們,所以我找不到一種方法來循環訪問數據。

我想爲所有記錄輸出標籤3,4和5(標題,名字,姓氏)。

我該如何做到這一點?

任何幫助表示讚賞

{ 
    "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" 
       ] 
      } 
     } 
     } 
    } 
} 

我可以訪問下面的代碼中的數據,但要避免投入17443,17444等

 $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

你有你自己嘗試新鮮事物或者是你在等待有人實現了這個要求? – Tomalak

+0

是的,我可以專門增加頂部的標籤,如 的foreach($ I $中data.17443) { 的foreach($在$ i.data.3 T) { 寫主機獲取數據$ t.value } 的foreach(在$ $ i.data.4 T) { 寫主機$ t.value } 的foreach(在$ $ i.data.5 T) { 寫主機$ t.value } } – Omen9876

+0

我用這個編輯了我的問題,所以它更有幫助 – Omen9876

回答

10

的PowerShell 3.0

在PowerShell中3.0和更高版本可以使用ConvertFrom-Json cmdlet來轉換一個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"} 
    } 
} 

現在我們可以遍歷對象圖,併產生輸出的對象的列表與TitleFirstNameLastName

$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 class處理JSON:

Add-Type -AssemblyName System.Web.Extensions 
$JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer 

現在我們可以做一個非常類似的操作 - 甚至有點簡單,因爲上面,因爲JavaScriptSerializer給你定期Dictionaries,這很容易遍歷經由鍵值對的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     

如果你從文件中讀取,使用Get-Content -Raw -Encoding UTF-8

  • -Raw因爲否則Get-Content返回各條線的陣列,並且JavaScriptSerializer.DeserializeObject無法處理。最近的Powershell版本似乎改進了.NET函數參數的類型轉換,所以它可能不會在您的系統上出錯,但如果它確實(或者只是爲了安全起見),請使用-Raw
  • -Encoding因爲在讀取文本文件時指定文本的編碼是明智的,UTF-8是JSON文件最可能的值。

如果您的JSON文件大於4 MB,請相應地設置JavaScriptSerializer.MaxJsonLength property


  • ConvertFrom-Json()爲您提供了一個PowerShell自定義對象(PSCustomObject)反映在JSON字符串的數據。
  • 您可以循環雖然自定義對象的與Get-Member -type NoteProperty
  • 屬性可以動態地使用$object."$propName"語法,或者$object."$(some PS expression)"訪問一個對象的屬性。
  • 您可以創建自己的自定義對象,並與New-Object PSObject -Property @{...}一堆屬性初始化它,或者[PSCustomObject]@{ .. } `
+0

謝謝你,那是我需要的 – Omen9876

-5

這裏有一個簡單的基於正則表達式的解決方案。假設$sRawJson包含您的JSON輸入:

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

接合部獲得全名:

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

你永遠不想用正則表達式來觸碰JSON。 – Tomalak

+0

也許根據你。還打了一個答案,輸出恰恰是什麼問題只是簡單的破壞性。 –

+1

我降低了無用和不明智的事情的答案。他們是否偶然輸出正確的東西完全是重點。我也下決心提示XML或HTML可以使用正則表達式進行分析,這是他們無法解析的 - 與JSON無法用正則表達式分析的原因完全相同。 – Tomalak