当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 在 PowerShell 中循环 JSON 文件 [2 种方法]

作者:精品下载站 日期:2024-12-14 05:31:36 浏览:13 分类:玩电脑

在 PowerShell 中循环 JSON 文件 [2 种方法]


[玩转系统] 在 PowerShell 中循环 JSON 文件 [2 种方法]

使用 ConvertFrom-Json Cmdlet

我们可以使用 ConvertFrom-Json cmdlet 来遍历具有第一级和嵌套级键的 JSON 文件;下面让我们来探讨一下。

遍历包含一级键的JSON文件

使用 ConvertFrom-Jsonforeach 循环来遍历仅具有第一级键的 JSON 文件。

file.json的内容:

{
    "name": "John Christoper",
    "age": 40,
    "city": "Washington"
}

将 ConvertFrom-Json 与 foreach 循环结合使用:

$jsonData = Get-Content -Path "./file.json" -Raw | ConvertFrom-Json
foreach ($current_property in $jsonData.PSObject.Properties) {
    Write-Host "$($current_property.Name): $($current_property.Value)"
}

输出 :

name: John Christoper
age: 40
city: Washington

我们使用 Get-Content cmdlet 读取位于 ./file.json 路径(我们使用 -Path参数。 -Raw 参数确保在传递给 ConvertFrom-Json cmdlet 之前将文件的全部内容作为单个字符串读取。

我们使用 ConvertFrom-Json cmdlet 将 JSON 字符串转换为 PowerShell 对象 (PSObject),并将其存储在 $jsonData 变量中。然后,我们使用 for 循环来迭代 $jsonData 中的所有属性。

我们如何检索所有属性?此表达式 $json.PSObject.Properties 以集合形式检索 $jsonData 对象的属性。

对于每个属性 ($current_property),我们使用 $current_property.Name$current_property.Value 来检索当前属性名称及其对应的值, 分别。

之后,我们通过将属性名称及其值组合为 "$ ($current_property.Name): $ ($current_property.Value)" 来构造一个字符串,以进一步在 PowerShell 上显示使用 Write-Host cmdlet 的控制台。

我们再举一个例子,不过这次我们会从用户那里获取密钥;请参见以下示例。

file.json的内容:

{
    "name": "John Christoper",
    "age": 40,
    "city": "Washington"
}

将 ConvertFrom-Json 与 foreach 循环结合使用:

$jsonData = Get-Content -Path "./file.json" -Raw | ConvertFrom-Json
$key = Read-Host -Prompt "Enter key"

foreach ($record in $jsonData) {
   if ($record |
       Select-Object -ExpandProperty $key -ErrorAction SilentlyContinue){
           Write-Host "$($record.$key)"
    }else{
           Write-Host "The given key was not found."
    }
}

输出:第一次运行:

Enter key: name
John Christopher

输出:第一次运行:

Enter key: random
The given key was not found.

同样,我们使用 Get-ContentConvertFrom-Json 读取 JSON 文件的内容并将其分配给 $jsonData 变量。之后,我们使用带有 -Prompt 参数的 Read-Host cmdlet 来提示用户并输入所需的密钥。我们将此密钥存储在 $key 变量中。

接下来,我们使用 foreach 循环(又名 foreach 语句)来迭代 $jsonData。在每次迭代中,我们使用 -ExpandProperty 参数将 $record 通过管道传输到 Select-Object cmdlet,以选择并展开 $key 给定的属性。代码>.

我们将 -ErrorAction 设置为 SilentlyContinue 以抑制错误消息,因为我们想要显示自定义消息而不是 PowerShell 生成的错误。

因此,如果 JSON 文件中存在 $key,则将执行 if 块中的 Write-Host cmdlet 以打印相应的价值;否则,将执行 else 块以在控制台上显示一条消息,指出未找到给定的已知内容。

让我们更深入地研究并使用带有嵌套键的 JSON 文件。

遍历包含一级键的JSON文件

使用 ConvertFrom-Jsonforeach 循环来遍历具有嵌套键的 JSON 文件。

file.json的内容:

{
    "student1": {
        "name": {
            "firstName": "John",
            "lastName": "Doe"
        },
        "age": 30,
        "Courses": {
            "CS123": "Introduction to Computer Science",
            "DS234": "Introduction to DataScience"
        }
    },
    "student2": {
        "name": {
            "firstName": "Thomas",
            "lastName": "Nelsan"
        },
        "age": 28,
        "Courses": {
            "CS123": "Java Programming",
            "Ph234": "Introduction to Psychology"
        }
    }
}

将 ConvertFrom-Json 与 ForEach 结合使用:

#Define a function named TraverseJson that takes a JSON object ($json)
#and an optional prefix ($prefix)
function TraverseJson($json, $prefix = '') {

    # Iterate over each property in the JSON object
    foreach ($property in $json.PSObject.Properties) {

        # Get the name and value of the property
        $propertyName = $property.Name
        $propertyValue = $property.Value

        # Check if the property value is a nested object
        if ($propertyValue -is [System.Management.Automation.PSCustomObject]) {

            # Check if it's the first level of keys
            if ($prefix -eq '') {
                # Display the available first-level keys
                Write-Host "First level keys:"
                foreach ($firstLevelKey in $json.PSObject.Properties.Name) {
                    Write-Host "- $firstLevelKey"
                }

                # Prompt the user to choose a first-level key
                $firstLevelKey = Read-Host "Choose a first level key (enter 'exit' to exit)"

                # If 'exit' is entered, return and exit the recursion
                if ($firstLevelKey -eq "exit") {
                    return
                }

                # If the chosen first-level key is valid
                elseif ($json.PSObject.Properties.Name -contains $firstLevelKey) {
                    # Get the available second-level keys for the chosen first-level key
                    $secondLevelKeys = $json.$firstLevelKey.PSObject.Properties.Name
                    Write-Host "Second level keys under '$firstLevelKey':"
                    foreach ($secondLevelKey in $secondLevelKeys) {
                        Write-Host "- $secondLevelKey"
                    }

                    # Prompt the user to choose a second-level key
                    $secondLevelKey = Read-Host "Choose a second level key (enter 'exit' to exit)"

                    # If 'exit' is entered, return and exit the recursion
                    if ($secondLevelKey -eq "exit") {
                        return
                    }

                    # If the chosen second-level key is valid
                    elseif ($secondLevelKeys -contains $secondLevelKey) {
                        # Get the nested value corresponding to the chosen keys
                        $nestedValue = $json.$firstLevelKey.$secondLevelKey
                        Write-Host "Value of '$firstLevelKey.$secondLevelKey': $nestedValue"
                    }

                    else {
                        Write-Host "Invalid second level key. Please try again."
                    }

                    # Recursively call the TraverseJson function with the
                    #nested value and an updated prefix
                    TraverseJson $json.$firstLevelKey.$secondLevelKey ($firstLevelKey + '.' + $secondLevelKey + '.')
                }
                else {
                    Write-Host "Invalid first level key. Please try again."
                }

                # Return to exit the recursion
                return
            }

            # If it's not the first level of keys
            else {
                # Recursively call the TraverseJson function with the
                #nested object and an updated prefix
                TraverseJson $propertyValue ($prefix + $propertyName + '.')
            }
        }

        # If the property value is an ArrayList
        elseif ($propertyValue -is [System.Collections.ArrayList]) {
            # Iterate over each item in the ArrayList
            $index = 0
            foreach ($item in $propertyValue) {
                #Recursively call the TraverseJson function with the item
                #and an updated prefix, including the array index
                TraverseJson $item ($prefix + $propertyName + "[$index].")
                $index++
            }
        }

        # If it's a regular property (not a nested object or ArrayList)
        else {
            # Display the key and value
            Write-Host "${prefix}${propertyName}: ${propertyValue}"
        }
    }
}

#Read the content of the JSON file and convert it to a JSON object
$json = Get-Content -Path "./file.json" -Raw | ConvertFrom-Json

#Call the TraverseJson function with the JSON object
TraverseJson $json

输出:第一次运行:

First level keys:
- student1
- student2
Choose a first level key from the options above (or enter 'exit' to exit): student1
Second level keys under 'student1':
- name
- age
- Courses
Choose a second level key from the options above (or enter 'exit' to exit): age
Value of 'student1.age': 30

输出:第二次运行:

First level keys:
- student1
- student2
Choose a first level key from the options above (or enter 'exit' to exit): student2
Second level keys under 'student2':
- name
- age
- Courses
Choose a second level key from the options above (or enter 'exit' to exit): Courses
Value of 'student2.Courses': @{CS123=Java Programming; Ph234=Introduction to Psychology}
student2.Courses.CS123: Java Programming
student2.Courses.Ph234: Introduction to Psychology

不要害怕查看代码;它非常简单明了;下面我们一步步来学习一下:

  • 首先,我们定义了 TraverseJson 函数,它有两个参数:$json 表示 JSON 对象,$prefiex 存储嵌套键的前缀。该函数递归遍历 JSON 对象并显示键值对。
  • TraverseJson 函数以 foreach 循环开始,该循环使用 $json.PSObject.Properties 迭代 $json 对象的属性
  • foreach 循环内,每个属性的名称和值分别分配给 $propertyName$propertyValue 变量。
  • 然后,上述代码使用 -is 运算符和类型 [System.Management.Automation.PSCustomObject].如果是,则代码进入 if 块。
  • if 块中的 $prefix 变量进行了额外检查。如果它是空字符串,我们就处于键的第一级。在本例中,代码通过迭代 $json.PSObject.Properties.Name 来显示可用的一级密钥,并提示用户选择一级密钥。
  • 如果用户输入exit,则函数返回并退出递归。否则,如果所选第一级密钥有效 ($json.PSObject.Properties.Name -contains $firstLevelKey),则代码会显示所选第一级密钥的可用第二级密钥。
  • 二级密钥从 $json.$firstLevelKey.PSObject.Properties.Name 获取并显示给用户。
  • 系统会提示用户选择二级密钥。如果输入exit,则函数返回并退出递归。如果所选的二级键有效 ($secondLevelKeys -contains $secondLevelKey),则代码使用 $json.$firstLevelKey.$secondLevelKey 检索相应的嵌套值并显示它。
  • 如果选择的二级密钥无效,则会显示错误消息,并提示用户重试。
  • 最后,TraverseJson 函数使用选定的嵌套值 ($json.$firstLevelKey.$secondLevelKey) 和更新的前缀 ($firstLevelKey + '. ' + $secondLevelKey + '.')。
  • 如果 $prefix 不为空(表示嵌套键),该函数会在嵌套对象 ($propertyValue) 上递归调用 TraverseJson,并更新前缀($prefix + $propertyName + '.')。
  • 如果 $propertyValue 是 ArrayList,则代码会进入 elseif 块并使用 foreach 循环迭代 ArrayList 中的每个项目。它使用包含数组索引的更新前缀对每个项目递归调用 TraverseJson
  • 如果 $propertyValue 既不是嵌套对象也不是 ArrayList,它会进入 else 块并使用 Write- 显示完整的键路径以及相应的值。主机 cmdlet。
  • 最后,在函数外部,代码使用 Get-Content cmdlet 读取 JSON 文件内容,使用 ConvertFrom-Json 将其转换为 JSON 对象,并调用 TraverseJson 函数与 JSON 对象。

因此,上面的代码允许用户交互地遍历 JSON 对象,选择不同级别的键,并查看其对应的值。此代码仅限于二级密钥;您可以为其添加价值以满足您的要求。

使用 ConvertFrom-Json 的重要性是什么?它迫使我们在上述每个解决方案中都使用它?由于 PowerShell 无法直接迭代 JSON 对象,因此我们使用 ConvertFrom-Json 将 JSON 字符串转换为 PSCustomObject,其中每个属性代表一个 JSON 字段。

如果您使用 PowerShell 3.0+ 版本,上述解决方案将有效;运行 $PSVersionTable.PSVersion 来检查您的 PowerShell 版本。如果您使用 PowerShell 版本 2.0 或正在寻找替代方案,以下解决方案适合您。

使用 JavaScriptSerializer 类

如果您使用的是 PowerShell 2.0 版,请使用 JavaScriptSerializer 类循环遍历 JSON。

使用 JavaScriptSerializer 类:

Add-Type -AssemblyName System.Web.Extensions
$JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$json = @'
[{"id":1,"firstName":"John","lastName":"Doe","age":32},
{"id":2,"firstName":"Thomas","lastName":"Christoper","age":30},{"id":3,"firstName":"Johny","lastName":"Daniel","age":29}]
'@
$data = $JS.DeserializeObject($json)
$data.GetEnumerator() | foreach-Object {
    foreach ($key in $_.Keys){
        Write-Host "$key : $($_[$key])"
    }
}

输出 :

id : 1
firstName : John
lastName : Doe
age : 32
id : 2
firstName : Thomas
lastName : Christoper
age : 30
id : 3
firstName : Johny
lastName : Daniel
age : 29

首先,我们使用 Add-Type 命令将 System.Web.Extensions 程序集加载到当前会话中。该程序集提供了用于在 .NET 应用程序中处理 JSON 数据的类。

然后,我们使用 New-Object cmdlet 从 System.Web.Script.Serialization 命名空间创建 JavaScriptSerializer 类的对象,并将其存储在 $JS 变量。

之后,我们使用了 $JS 对象的 DeserializeObject() 方法。该方法将 JSON 字符串 ($json) 作为参数,将其反序列化为 PowerShell 对象。我们将结果对象存储在 $data 变量中。

接下来,我们使用 GetEnumerator() 方法和 foreach-Object cmdlet 循环访问 $data 中的每个项目。在 foreach-Object 内部,我们使用 foreach 循环与当前项的 Keys 属性来迭代当前项中的每个键。我们使用 Write-Host cmdlet 显示相应的键值对。

这就是如何在 PowerShell 中循环 JSON 文件的全部内容。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯