json - 遍历 JSON 文件 PowerShell

标签 json powershell powershell-5.0

我正在尝试在 PowerShell 中遍历以下 JSON 文件。

没有具体命名顶部标签(例如 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
   }
}

最佳答案

PowerShell 3.0+

在 PowerShell 3.0 及更高版本(参见:Determine installed PowerShell version)中,您可以使用 ConvertFrom-Json cmdlet 将 JSON 字符串转换为 PowerShell 数据结构。

这既方便又不幸——方便,因为很容易消费 JSON,不幸的是,ConvertFrom-Json 给你 PSCustomObjects ,并且它们很难作为键值对进行迭代。

当您知道 key 时,就没有什么可迭代的了 - 您只需直接访问它们,例如$result.thisKey.then.thatKey.array[1],你就完成了。

但在这个特定的 JSON 中,键似乎是动态的/提前不知道的,例如 "17443""17444"。这意味着我们需要能够将 PSCustomObject 转换为 foreach 可以理解的键值列表的东西。

# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMember {
    [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-ObjectMember | foreach {
    $_.Value | Get-ObjectMember | 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 / Alternative approach

An alternative approach that also works for PowerShell 2.0 (which does not support some of the constructs above) would involve using the .NET JavaScriptSerializer class to handle the 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                 

如果您的 JSON 大于 4 MB,请设置 JavaScriptSerializer.MaxJsonLength property相应地。


关于从文件中读取 JSON

如果从文件中读取,请使用 Get-Content -Raw -Encoding UTF-8

  • -Raw 因为否则 Get-Content 返回一个单独的行数组,而 JavaScriptSerializer.DeserializeObject 无法处理。最近的 Powershell 版本似乎改进了 .NET 函数参数的类型转换,因此它可能不会在您的系统上出错,但如果确实如此(或只是为了安全起见),请使用 -Raw
  • -Encoding 因为在读取文本文件时指定其编码是明智的,而 UTF-8 是 JSON 文件最可能的值。

注意事项

  • 当您构建包含具有不可预测键的项目的 JSON 时,更喜欢像 {items: [{key: 'A', value: 0}, {key: 'B', value: 1}] 这样的数组结构}{'A': 0, 'B': 1} 之上。后者似乎更直观,但它既难以生成,也更难以使用。
  • ConvertFrom-Json() 为您提供反射(reflect) JSON 字符串中数据的 PowerShell 自定义对象 (PSCustomObject)。
  • 您可以使用 Get-Member -type NoteProperty
  • 循环自定义对象的属性
  • 您可以使用 $object."$propName" 语法或 $object."$(some PS expression)" 动态访问对象的属性。
  • 您可以创建自己的自定义对象并使用 New-Object PSObject -Property @{...}[PSCustomObject]@{ .. } `

关于json - 遍历 JSON 文件 PowerShell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33520699/

相关文章:

java - JPA 无法使用 START_OBJECT TOKEN 作为搜索键

powershell - Teamcity - 从 Powershell 生成工件

powershell - 开始/处理/结束如何节省对foreach的需求?还需要该参数吗?

windows - 在 Windows 10 中使用 powershell 在多个桌面上启动程序

powershell - 使用robocopy搜索子目录

java - Android 可打包列表<String[]>

java - 使用 Jackson 忽略 JSON 对象上的新字段

json - ConvertFrom-Json 返回 "Cannot process argument because the value of argument "名称“无效”。

powershell - 如何替换连续的特殊字符?

PowerShell v5 - 如何将模块安装到没有互联网连接的计算机上?