【问题标题】:How can I parse JSON with comments using System.Text.Json?如何使用 System.Text.Json 解析带有注释的 JSON?
【发布时间】:2019-12-22 19:00:00
【问题描述】:

我有一些包含 cmets 的 JSON(尽管在 JSON spec 中不严格允许 cmets。)如何使用 System.Text.Json 解析这个 JSON?

我收到的 JSON 如下:

// A person
{
    "Id" : 1 /* Person's ID */,
    "Name" : "Foo" // Person's name
}

当我尝试将其加载到 JsonDocument 中时:

using var doc = JsonDocument.Parse(jsonString);

我得到以下异常:

System.Text.Json.JsonReaderException: '/' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)```

当我尝试使用 JsonSerializer 反序列化时:

var person = JsonSerializer.Deserialize<Person>(jsonString);

我遇到了类似的异常:

System.Text.Json.JsonException: '/' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
 ---> System.Text.Json.JsonReaderException: '/' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)

如何使用System.Text.Json 解析或反序列化此 JSON?

【问题讨论】:

  • 从技术上讲,它不是合法的 JSON,因为官方的 JSON 语法不支持 cmets。尽管如此,大多数 JSON 解析器都支持至少忽略 cmets。
  • 同意。使对 cme​​ts 的支持成为非默认选项是明智的,因为它们不在官方语法中。

标签: c# json system.text.json


【解决方案1】:

包含 cmets 的 JSON 可以由 System.Text.Json 解析,但默认情况下此类 JSON 被视为无效,可能是因为 cmets 不包含在 JSON standard 中。不过,可以通过修改选项中的 JsonCommentHandling 枚举来启用对 cme​​ts 的支持:

Disallow   0   Doesn't allow comments within the JSON input. 
               Comments are treated as invalid JSON if found, and a JsonException is thrown. 
               This is the default value.

Skip       1   Allows comments within the JSON input and ignores them. 
               The Utf8JsonReader behaves as if no comments are present.

Allow      2   Allows comments within the JSON input and treats them as valid tokens. 
               While reading, the caller can access the comment values.

要在使用Utf8JsonReader 直接读取时启用cmets 的跳过或加载,请将JsonReaderOptions.CommentHandling 设置为Utf8JsonReader constructors 之一,例如如下:

static List<string> GetComments(string jsonString)
{
    var options = new JsonReaderOptions 
    { 
        CommentHandling = JsonCommentHandling.Allow 
    };
    var list = new List<string>();
    var reader = new Utf8JsonReader(new ReadOnlySpan<byte>(Encoding.UTF8.GetBytes(jsonString)), options);
    while (reader.Read())
        if (reader.TokenType == JsonTokenType.Comment)
            list.Add(reader.GetComment());
    return list;
}

使用JsonDocument解析时设置JsonDocumentOptions.CommentHandling = JsonCommentHandling.Skip

var options = new JsonDocumentOptions
{
    CommentHandling = JsonCommentHandling.Skip,
};
using var doc = JsonDocument.Parse(jsonString, options);

使用JsonSerializer 反序列化时设置JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip

var options = new JsonSerializerOptions
{
    ReadCommentHandling = JsonCommentHandling.Skip
};
var person = JsonSerializer.Deserialize<Person>(jsonString, options);

请注意,从 .NET Core 3.1 开始,JsonDocumentJsonSerializer 仅支持跳过或禁止 cmets;他们不支持加载它们。如果你尝试设置JsonCommentHandling.Allow,你会得到一个异常:

System.ArgumentOutOfRangeException: Comments cannot be stored in a JsonDocument, only the Skip and Disallow comment handling modes are supported. (Parameter 'value')
System.ArgumentOutOfRangeException: Comments cannot be stored when deserializing objects, only the Skip and Disallow comment handling modes are supported. (Parameter 'value')

(这意味着在编写JsonConverter&lt;T&gt;.Read() 方法时不需要手动跳过 cmets,与 Newtonsoft 相比,它简化了注释处理,其中 cmets 暴露于 ReadJson() 并且每次读取令牌时都必须检查.)

更多信息请见How to serialize and deserialize JSON in .NET : Allow comments and trailing commas

演示小提琴here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-09
    • 2021-11-08
    • 2019-02-13
    • 2016-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多