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 允许复制和修改。因此,您应该能够创建自己的public class StricterJsonTextReader : JsonReader,复制自JsonTextReader,并修改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 版本,自己构建,然后使用它来代替官方版本。无论哪种方式,请务必从您要使用的版本中分叉源代码:
作为创建自己的解析器的替代方法,您可以使用 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'}")
相关链接: