在PowerShell中了解NewtonSoft [英] Understanding NewtonSoft in PowerShell

查看:41
本文介绍了在PowerShell中了解NewtonSoft的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我涉足JSON解析和NewtonSoft领域,至少可以这样说,我很困惑.

I making a foray into the world of JSON parsing and NewtonSoft and I'm confused, to say the least.

采用以下PowerShell脚本:

Take the below PowerShell script:

$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根父级.

I'd like to be able to find the name of the root parent for any given position. So above, I'd like to know that the item I'm looking at (Array2Object1Str1) belongs to the Array2 root parent.

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

I think I'm not understanding some fundamentals here. Is it possible to determine the root parent? Also, any help in understanding my comments in the script would be great. Namely why I can't return things like path or parent, but can see it when I debug in VSCode.

推荐答案

dbc的答案包含有用的背景信息,并使显然,从PowerShell调用NewtonSoft Json.NET库很麻烦.

dbc's answer contains helpful background information, and makes it clear that calling the NewtonSoft Json.NET library from PowerShell is cumbersome.

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

Given PowerShell's built-in support for JSON parsing - via the ConvertFrom-Json and ConvertTo-Json cmdlets - there is usually no reason to resort to third-party libraries (directly[1]), except in the following cases:

  • 性能至关重要时.
  • 必须克服PowerShell JSON解析的限制(缺少对空键名和仅字母大小写不同的键的支持).
  • 需要使用Json.NET类型及其方法,而不是使用无方法的属性袋" [pscustomobject]实例ConvertFrom-Json构造时.
  • When performance is paramount.
  • When the limitations of PowerShell's JSON parsing must be overcome (lack of support for empty key names and keys that differ in letter case only).
  • When you need to work with the Json.NET types and their methods rather than with the method-less "property-bag" [pscustomobject] instances ConvertFrom-Json constructs.

直接在PowerShell中使用NewtonSoft的Json.NET是尴尬,但如果您观察到一些规则,则是可管理的. :

While working with NewtonSoft's Json.NET directly in PowerShell is awkward, it is manageable, if you observe a few rules:

  • 缺少可见的输出不一定 表示根本没有任何输出:

  • Lack of visible output doesn't necessarily mean that there isn't any output at all:

  • 由于在PowerShell中 bug (自v7.0.0-preview.4起),[JValue]实例和包含它们的[JProperty]实例默认情况下不会产生可见输出 改为访问其(严格键入的).Value属性(例如,$nsObj.Array1[0].Value$nsProp.Value.Value(原文如此))

  • Due to a bug in PowerShell (as of v7.0.0-preview.4), [JValue] instances and [JProperty] instances containing them produce no visible output by default; access their (strongly typed) .Value property instead (e.g., $nsObj.Array1[0].Value or $nsProp.Value.Value (sic))

输出[JObject]/[JArray]/[JProperty]/[JValue]实例的字符串表示,请不要依赖于输出-is(例如,$nsObj),使用带有.ToString() 的显式字符串化(例如,$nsObj.ToString());

To output the string representation of a [JObject] / [JArray] / [JProperty] / [JValue] instance, do not rely on output as-is (e.g, $nsObj), use explicit stringification with .ToString() (e.g., $nsObj.ToString()); while string interpolation (e.g., "$nsObj") does generally work, it doesn't with [JValue] instances, due to the above-mentioned bug.

[JObject][JArray]对象显示其 elements 实例属性的列表(将Format-List隐式应用于对象的枚举).对象);您可以使用Format-* cmdlet调整输出形状;例如$nsObj | Format-Table Path, Type.

[JObject] and [JArray] objects by default show a list of their elements' instance properties (implied Format-List applied to the enumeration of the objects); you can use the Format-* cmdlets to shape output; e.g., $nsObj | Format-Table Path, Type.

  • 由于 另一个错误 (可能有相同的根本原因),从PowerShell Core 7.0.0-preview.4开始,在输入JSON包含 array [JObject]实例的默认输出实际上是 breaking . >(打印错误format-default : Target type System.Collections.IEnumerator is not a value type or a non-abstract class. (Parameter 'targetType')).
  • Due to another bug (which may have the same root cause), as of PowerShell Core 7.0.0-preview.4, default output for [JObject] instances is actually broken in cases where the input JSON contains an array (prints error format-default : Target type System.Collections.IEnumerator is not a value type or a non-abstract class. (Parameter 'targetType')).

要通过数字索引到[JObject]实例中,即通过 index 而不是通过名称访问属性,请使用以下惯用法: @($nsObj)[<n>] ,其中<n>是感兴趣的数字索引.

To numerically index into a [JObject] instance, i.e. to access properties by index rather than by name, use the following idiom: @($nsObj)[<n>], where <n> is the numerical index of interest.

  • $nsObj[<n>]实际上应该起作用,因为与C#不同,PowerShell将通过接口实现的成员公开为可直接调用的类型成员,因此 numeric通过JObject接口实现的JObject索引器应该可以访问,但是由于此错误(自PowerShell Core 7.0.0-preview.4起).

  • $nsObj[<n>] actually should work, because, unlike C#, PowerShell exposes members implemented via interfaces as directly callable type members, so the numeric indexer that JObject implements via the IList<JToken> interface should be accessible, but isn't, presumably due to this bug (as of PowerShell Core 7.0.0-preview.4).

基于PowerShell c的数组子表达式运算符@(...)的变通办法强制[JObject]实例的枚举产生其[JProperty]成员的数组,然后可以通过索引对其进行访问;请注意,这种方法是简单,但效率不高,因为枚举和构造了aux.发生阵列;但是,鉴于单个JSON对象(与 array 相对)通常不具有大量属性,因此在实践中这不太可能重要.
一种基于反射的解决方案可以访问IList<JToken>界面的数字索引器,但可能甚至更慢.

The workaround based on @(...), PowerShell's array-subexpression operator, forces enumeration of a [JObject] instance to yield an array of its [JProperty] members, which can then be accessed by index; note that this approach is simple, but not efficient, because enumeration and construction of an aux. array occurs; however, given that a single JSON object (as opposed to an array) typically doesn't have large numbers of properties, this is unlikely to matter in practice.
A reflection-based solution that accesses the IList<JToken> interface's numeric indexer is possible, but may even be slower.

请注意,可能再次需要基于.Value的其他访问权限才能打印结果(或提取强类型属性 value ). p>

Note that additional .Value-based access may again be needed to print the result (or to extract the strongly typed property value).

通常,不要使用.GetEnumerator()方法 [JObject][JArray]实例可直接 枚举.

Generally, do not use the .GetEnumerator() method; [JObject] and [JArray] instances are directly enumerable.

  • 请记住, PowerShell可能会自动枚举此类实例,在您不期望的情况下,尤其是在管道中;尤其是,当您将[JObject]发送到管道时,它的组成部分[JProperty]会单独发送.
  • Keep in mind that PowerShell may automatically enumerate such instances in contexts where you don't expect it, notably in the pipeline; notably, when you send a [JObject] to the pipeline, it is its constituent [JProperty]s that are sent instead, individually.

使用类似@($nsObj.Array1).Value的方法提取原始 JSON值(字符串,数字等)数组的 values -即,[JValue]实例-作为数组.

Use something like @($nsObj.Array1).Value to extract the values of an array of primitive JSON values (strings, numbers, ...) - i.e, [JValue] instances - as an array.

下面在上下文中演示了这些技术:

The following demonstrates these techniques in context:

$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.


[1] PowerShell Core - but not Windows PowerShell - currently (v7) actually uses NewtonSoft's Json.NET behind the scenes.

这篇关于在PowerShell中了解NewtonSoft的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆