json - 在PowerShell中了解NewtonSoft

标签 json powershell json.net

至少可以说,我涉足JSON解析和NewtonSoft Realm 。

请使用以下PowerShell脚本:

$json = @"
{
    "Array1": [
        "I am string 1 from array1",
        "I am string 2 from array1"
    ],   

    "Array2": [
        {
           "Array2Object1Str1": "Object in list, string 1",
           "Array2Object1Str2": "Object in list, string 2"
        }
    ]

}
"@

#The newtonSoft way
$nsObj = [Newtonsoft.Json.JsonConvert]::DeserializeObject($json, [Newtonsoft.Json.Linq.JObject])

$nsObj.GetType().fullname #Type = Newtonsoft.Json.Linq.JObject

$nsObj[0] #Returns nothing. Why?

$nsObj.Array1 #Again nothing. Maybe because it contains no key:value pairs?
$nsObj.Array2 #This does return, maybe because has object with kv pairs

$nsObj.Array2[0].Array2Object1Str1 #Returns nothing. Why? but...
$nsObj.Array2[0].Array2Object1Str1.ToString() #Cool. I get the string this way.

$nsObj.Array2[0] #1st object has a Path property of "Array2[0].Array2Object1Str1" Great!

foreach( $o in $nsObj.Array2[0].GetEnumerator() ){
    "Path is: $($o.Path)"
    "Parent is: $($o.Parent)"
} #??? Why can't I see the Path property like when just output $nsObj.Array2[0] ???
#How can I find out what the root parent (Array2) is for a property? Is property even the right word?

我希望能够找到任何给定位置的根父级名称。因此,在上面,我想知道我正在查看的项目(Array2Object1Str1)属于Array2根父级。

我认为我在这里不了解一些基本知识。是否可以确定根父级?另外,对理解我在脚本中的注释的任何帮助都将非常有用。这就是为什么我无法返回诸如path或parent之类的东西,但是在VSCode中进行调试时却可以看到它的原因。

最佳答案

dbc's answer包含有用的背景信息,并且很清楚,从PowerShell调用NewtonSoft Json.NET库很麻烦。

鉴于PowerShell对JSON解析的内置支持-通过ConvertFrom-JsonConvertTo-Json cmdlet-,在以下情况下,通常没有理由诉诸第三方库(direct [1]),除外。

  • 性能最重要时。
  • 当必须克服PowerShell JSON解析的限制时(缺少对空键名和仅字母大小写不同的键的支持)。
  • 当您使用时,需要使用Json.NET类型及其方法,而不是使用无方法的“属性袋” [pscustomobject]实例ConvertFrom-Json构造。

  • 如果直接在PowerShell中使用NewtonSoft的Json.NET很难,但是如果遵守一些规则,它是可管理的:
  • 缺少可见的输出并不一定意味着根本没有任何输出:
  • 由于存在bug in PowerShell(从v7.0.0-preview.4开始),因此[JValue]实例和包含它们的[JProperty]实例默认情况下不会产生可见输出访问其(严格键入的).Value属性,而不是(例如$nsObj.Array1[0].Value$nsProp.Value.Value(原文如此))
  • 输出[JObject] / [JArray] / [JProperty] / [JValue]实例的字符串表示形式,请不要按原样输出(例如$nsObj),使用带有.ToString() (例如)的显式字符串化;尽管字符串插值(例如$nsObj.ToString())通常可以正常工作,但由于上述错误,它不适用于"$nsObj"实例。
  • 默认情况下,
  • [JValue][JObject]对象显示其元素的实例属性的列表(隐式[JArray]应用于对象的枚举);您可以使用Format-List cmdlet来调整输出的形状;例如Format-*
  • 由于another bug(可能具有相同的根本原因),自PowerShell Core 7.0.0-preview.4起,在输入JSON包含数组的情况下,$nsObj | Format-Table Path, Type实例的默认输出实际上已损坏(打印错误[JObject])。
  • 要通过数字索引到format-default : Target type System.Collections.IEnumerator is not a value type or a non-abstract class. (Parameter 'targetType')实例中,即通过索引而不是名称来索引访问属性,请使用以下惯用语: [JObject] ,其中@($nsObj)[<n>]是感兴趣的数字索引。
  • <n>实际上应该可以工作,因为与C#不同,PowerShell将通过接口(interface)实现的成员公开为可直接调用的类型成员,因此$nsObj[<n>]通过JObject接口(interface)实现的数字索引器应该可以访问,但可能不是由于this bug(自PowerShell Core 7.0.0-preview.4)。
  • 解决方案基于PowerShell的array-subexpression运算符IList<JToken>,强制枚举@(...)实例产生其[JObject]成员数组,然后可以通过索引对其进行访问;请注意,此方法很简单,但效率不高,因为枚举和构造了aux。发生阵列;但是,考虑到单个JSON对象(而不是数组)通常不具有大量属性,因此在实践中这不太可能。
    一种基于反射的解决方案可以访问[JProperty]接口(interface)的数字索引器,但可能更慢。
  • 注意,可能再次需要基于IList<JToken>的其他访问才能打印结果(或提取强类型属性值)。
  • 通常,不使用.Value方法 .GetEnumerator()[JObject]实例直接可枚举
  • 请记住,PowerShell可能会在您不期望的情况下(尤其是在管道中)自动枚举此类实例;值得注意的是,当您将[JArray]发送到管道时,发送的是它的组成[JObject],而不是单独发送
  • 使用诸如[JProperty]之类的东西来提取原始JSON值(字符串,数字等)数组的值(即@($nsObj.Array1).Value实例)作为数组。

  • 下面在上下文中演示了这些技术:
    $json = @"
    {
        "Array1": [
            "I am string 1 from array1",
            "I am string 2 from array1",
        ],
    
        "Array2": [
            {
               "Array2Object1Str1": "Object in list, string 1",
               "Array2Object1Str2": "Object in list, string 2"
            }
        ]
    
    }
    "@
    
    # Deserialize the JSON text into a hierarchy of nested objects.
    # Note: You can omit the target type to let Newtonsoft.Json infer a suitable one.
    $nsObj = [Newtonsoft.Json.JsonConvert]::DeserializeObject($json)
    # Alternatively, you could more simply use:
    #   $nsObj = [Newtonsoft.Json.Linq.JObject]::Parse($json)
    
    # Access the 1st property *as a whole* by *index* (index 0).
    @($nsObj)[0].ToString()
    
    # Ditto, with (the typically used) access by property *name*.
    $nsObj.Array1.ToString()
    
    # Access a property *value* by name.
    $nsObj.Array1[0].Value
    
    # Get an *array* of the *values* in .Array1.
    # Note: This assumes that the array elements are JSON primitives ([JValue] instances.
    @($nsObj.Array1).Value
    
    # Access a property value of the object contained in .Array2's first element by name:
    $nsObj.Array2[0].Array2Object1Str1.Value
    
    
    # Enumerate the properties of the object contained in .Array2's first element
    # Do NOT use .GetEnumerator() here - enumerate the array *itself*
    foreach($o in $nsObj.Array2[0]){
      "Path is: $($o.Path)"
      "Parent is: $($o.Parent.ToString())"
    }
    

    [1] PowerShell Core-但不是Windows PowerShell-当前(v7)实际上在幕后使用NewtonSoft的Json.NET。

    关于json - 在PowerShell中了解NewtonSoft,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58141125/

    相关文章:

    php - 我如何在我的应用程序中使用 json?

    json - 是否可以在不安装 Play 的情况下使用 JSON 库?

    javascript - 如何使用 javascript 读取此 JSON 并获取值?

    loops - 循环直到 IP :port is responding

    c# - 如何在两个不同的类上使用相同的 JsonProperty 名称

    javascript - 简单解释EINVALIDTAGNAME?

    c++ - 已设置 MinGW 路径但未在 Powershell 中找到

    powershell - 如何使用 Ansible 中的自定义事实从 Windows 主机检索已安装软件的列表

    c# - 从给定的 JSON 文件中检索特定属性

    c# - 将值转换为类型的 JSON 错误