.net - 如何在 JSON .NET 上对属性名称强制使用引号

标签 .net json json.net jsonparser

我正在使用 Json.NET 解析我收到的一些 JSON,并将其发送到我的应用程序上的端点。

我希望以下 JSON 对象解析失败,因为它的属性名称上没有引号:

{
  foo: "bar"
}

JToken.Parse() 表示它是有效的 JSON。但是,当我使用online parser时我收到以下错误

Strings should be wrapped in double quotes.

有没有办法让 JSON .NET 强制执行此规则?

最佳答案

Json.NET 目前没有实现对 JSON 属性名称的严格解析。

在内部 JToken.Parse() 构造一个 JsonTextReader解析 JSON 字符串,并且当前无法禁用 JsonTextReader 解析不带引号的属性名称的功能。

通过 JsonTextReader.Read() 迭代 JSON 文件时,方法 JsonTextReader.ParseProperty() 用于解析属性名称:

Newtonsoft.Json.JsonTextReader.ParseUnquotedProperty() 
Newtonsoft.Json.JsonTextReader.ParseProperty() 
Newtonsoft.Json.JsonTextReader.ParseObject() 
Newtonsoft.Json.JsonTextReader.Read() 
Newtonsoft.Json.Linq.JContainer.ReadTokenFrom()

而且,从 current reference source 可以看出,此方法自动处理双引号、单引号和不带引号的属性:

private bool ParseProperty()
{
    char firstChar = _chars[_charPos];
    char quoteChar;

    if (firstChar == '"' || firstChar == '\'')
    {
        _charPos++;
        quoteChar = firstChar;
        ShiftBufferIfNeeded();
        ReadStringIntoBuffer(quoteChar);
    }
    else if (ValidIdentifierChar(firstChar))
    {
        quoteChar = '\0';
        ShiftBufferIfNeeded();
        ParseUnquotedProperty();
    }
    else
    {
        throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
    }

    // REMAINDER OMITTED

如您所见,没有选项可以配置读取器以引发非双引号属性的异常。

作为解决方法current Json.NET license允许复制和修改。因此,您应该能够创建自己的从 JsonTextReader 复制的 公共(public)类 StricterJsonTextReader : JsonReader,并按如下方式修改 ParseProperty():

private bool ParseProperty()
{
    char firstChar = _chars[_charPos];
    char quoteChar;

    if (firstChar == '"')
    {
        _charPos++;
        quoteChar = firstChar;
        ShiftBufferIfNeeded();
        ReadStringIntoBuffer(quoteChar);
    }
    else
    {
        // JsonReaderException.Create() is an internal static method,
        // so you will need to replace this with some extension method
        throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos]));
    }

但是,这可能不是一件完全容易的工作,因为 JsonTextReader 广泛使用 Src/Newtonsoft.Json/Utilities 中的实用程序目录。您应该预算几天来制作必要实用程序的最小副本。

或者,您可以派生自己的 Json.NET 版本,自己构建它,然后使用它来代替官方版本。无论哪种方式,请务必从您要使用的版本中 fork 源代码:

Select the correct version

作为创建自己的解析器的替代方案,您可以使用 JsonReaderWriterFactory.CreateJsonReader() 预处理 JSON。确保严格遵守JSON标准:

public static class JsonExtensions
{
    public static JToken StrictParse(string json)
    {
        try
        {
            // Throw an exception if the json string is not in strict compliance with the JSON standard
            // by tokenizing it with the JSON reader used by DataContractJsonSerializer:
            using (var stream = GenerateStreamFromString(json))
            using (var reader = System.Runtime.Serialization.Json.JsonReaderWriterFactory.CreateJsonReader(stream, System.Xml.XmlDictionaryReaderQuotas.Max))
            {
                while (reader.Read())
                {
                }
            }
        }
        catch (Exception ex)
        {
            // Wrap the XmlException in a JsonReaderException
            throw new JsonReaderException("Invalid JSON", ex);
        }
        // Then actually parse with Json.NET
        return JToken.Parse(json);
    }

    static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
    }
}

(您需要添加对适合您的框架的 .Net 程序集的引用。)

性能会更差,因为您将有效地解析 JSON 两次,但实现工作微不足道。

奇怪的是,我无法使用 JavaScriptSerializer 来检查严格的 JSON 合规性,因为它也接受不带引号的属性名称!

// The following does not throw an exception:
new System.Web.Script.Serialization.JavaScriptSerializer().DeserializeObject("{foo : 'bar'}")

相关链接:

关于.net - 如何在 JSON .NET 上对属性名称强制使用引号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53304218/

相关文章:

c# - 在 Linq 中使用 Expression<Func<T,X>> 包含扩展

c# - 嵌套模型上的 nullReferenceException

c# - Selenium - 异常 - 连接关闭

c# - Json.net忽略子对象的空值

c# - 带有 StringComparer 序列化的 Json.NET Dictionary<string,T>

c# - JSON.NET反序列化自定义日期格式

c# - ADO.NET 数据服务

json - 以 JsonFormat 模式编写正则表达式

java - 如何在 Java 中将 hashmap 转换为 JSON 对象

c# - 如何直接从流反序列化非常大的 JSON 数据而不是一次加载整个 json