dbc 的回答包含有用的背景信息,并清楚地表明从 PowerShell 调用 NewtonSoft Json.NET 库很麻烦。
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:
- When 表现是最重要的。
- 当。。。的时候PowerShell JSON 解析的局限性必须克服(缺乏对空键名称和仅字母大小写不同的键的支持)。
- 当你需要使用 Json.NET 类型及其方法,而不是无方法的“财产袋”
[pscustomobject]
实例ConvertFrom-Json
结构体。
直接在 PowerShell 中使用 NewtonSoft 的 Json.NET 是awkward, it is 易于管理的,如果你观察一些rules:
-
Lack of visible输出没有一定意味着根本没有任何输出:
由于一个bug在 PowerShell 中(从 v7.0.0-preview.4 开始),[JValue]
实例和[JProperty]
包含它们的实例产生无可见输出默认情况下; 访问他们的(强类型).Value
财产代替 (e.g., $nsObj.Array1[0].Value
or $nsProp.Value.Value
(sic))
To 输出string表示 of a [JObject]
/ [JArray]
/ [JProperty]
/ [JValue]
例如,不要依赖原样输出(例如,$nsObj
), 使用显式字符串化.ToString()
(e.g., $nsObj.ToString()
);而字符串插值(例如,"$nsObj"
) does 一般来说工作,它不与[JValue]
实例,由于上述错误。
-
[JObject]
and [JArray]
对象默认显示其列表elements' 实例属性(隐含Format-List
应用于枚举的对象);你可以use the Format-*
用于调整输出的 cmdlet; e.g., $nsObj | Format-Table Path, Type
.
- Due to 另一个错误(可能具有相同的根本原因),从 PowerShell Core 7.0.0-preview.4 开始,默认输出为
[JObject]
实例实际上是broken如果输入 JSON 包含array(打印错误format-default : Target type System.Collections.IEnumerator is not a value type or a non-abstract class. (Parameter 'targetType')
).
-
以数字方式索引到[JObject]
实例,即访问属性通过index不要使用名称,而是使用以下惯用语:@($nsObj)[<n>]
, where <n>
是感兴趣的数字索引。
$nsObj[<n>]
实际上should有效,因为与 C# 不同,PowerShell 公开了实现的成员通过接口作为可直接调用的类型成员,因此numeric索引器JObject
通过实施IList<JToken>
接口应该是可访问的,但实际上却不是,大概是因为this bug(从 PowerShell Core 7.0.0-preview.4 开始)。
解决方法基于@(...)
,PowerShell 的数组子表达式运算符,强制枚举[JObject]
实例产生其数组[JProperty]
成员,然后可以通过索引访问;请注意,这种方法是simple, but 效率不高,因为 aux 的枚举和构造。数组出现;然而,考虑到单个 JSON 对象(而不是array)通常不具有大量属性,这在实践中不太重要。
基于反射的解决方案,可访问IList<JToken>
接口的数字索引器是可能的,但甚至可能更慢。
请注意,额外的.Value
可能再次需要基于访问print结果(或提取强类型属性value).
-
一般来说,不要使用.GetEnumerator()
method; [JObject]
and [JArray]
实例是directly可枚举的.
- 请记住PowerShell 可能自动地列举这样的例子在你意想不到的情况下,特别是在pipeline;尤其,当你发送一个
[JObject]
对于管道来说,它是它的组成部分[JProperty]
而是单独发送的.
使用类似的东西@($nsObj.Array1).Value
来提取values的数组的原始JSON 值(字符串、数字……) - 即,[JValue]
实例 - 作为数组。
下面在上下文中演示了这些技术:
$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 - but not Windows PowerShell - currently (v7) actually uses NewtonSoft's Json.NET behind the scenes.