如何使用System.Text.Json解析带注释的JSON?

19

我有一些包含注释的JSON(尽管在JSON规范中严格禁止使用注释)。我如何使用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语法不支持注释。尽管如此,大多数JSON解析器至少支持忽略注释。 - Lasse V. Karlsen
同意。将对注释的支持设置为非默认选项是明智的,因为它们不在官方语法中。 - dbc
1个回答

33

包含注释的 JSON 可以被 System.Text.Json 解析,但是默认情况下这样的 JSON 被认为是无效的,可能是因为注释没有包含在 JSON 标准 中。不过,可以通过修改选项中的 JsonCommentHandling 枚举来启用对注释的支持:

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直接读取时启用跳过或加载注释,请在其中一个Utf8JsonReader构造函数中设置JsonReaderOptions.CommentHandling,例如:

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仅支持跳过或禁止注释,不支持加载注释。如果您尝试为其中任何一个设置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<T>.Read()方法时,无需手动跳过注释,与Newtonsoft相比,简化了注释处理,因为注释暴露给ReadJson(),每次读取令牌时必须进行检查。更多信息请参见如何在.NET中序列化和反序列化JSON:允许注释和尾随逗号。演示fiddle 在此处

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接