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

时间:2019-12-22 19:00:00

标签: c# json system.text.json

我有一些包含注释的JSON(即使JSON spec中严格禁止使用注释。)如何使用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?

1 个答案:

答案 0 :(得分:4)

包含注释的

JSON可以由System.Text.Json进行解析,但默认情况下此类JSON被认为无效,这可能是因为注释未包含在JSON standard中。不过,可以通过修改选项中的 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直接阅读时启用跳过或加载注释,请在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仅支持跳过或禁止注释;他们不支持加载它们。如果您尝试为其中一个设置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相比,简化了注释处理,在Newtonsoft中,注释ReadJson()公开并且每次都要检查令牌被读取。)

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

演示小提琴here