Как установить кавычки в именах свойств в JSON .NET

Я использую Json.NET для синтаксического анализа полученного JSON на конечную точку моего приложения.

Я хочу, чтобы следующий объект JSON не прошел синтаксический анализ, поскольку в его имени свойства нет кавычек:

{
  foo: "bar"
}

JToken.Parse() говорит, что это действительный JSON. Однако, когда я использовал онлайн-анализатор, я получаю следующую ошибку

Строки следует заключать в двойные кавычки.

Есть ли способ заставить JSON .NET применять это правило?


person paddingtonMike    schedule 14.11.2018    source источник
comment
Проблема с этим ответом в том, что он не показывает подходящий способ реализации решения. Я взглянул на класс JsonTextReader из JSON .NET и не уверен, что мне нужно делать. Я не могу поверить, что такая популярная библиотека, как JSON .NET, не может поддерживать строгий парсинг.   -  person paddingtonMike    schedule 14.11.2018
comment
Также по теме: Имя свойства json без кавычек. На этот вопрос так и не ответили, но в комментарии говорится: Это не похоже на то. Должен ли я дать ответ с некоторыми дополнительными подробностями о том, как форк JsonTextReader, чтобы делать то, что вам нужно?   -  person dbc    schedule 14.11.2018
comment
Это было бы очень полезно, спасибо.   -  person paddingtonMike    schedule 14.11.2018
comment
Ответ добавлен и обновлен.   -  person dbc    schedule 14.11.2018


Ответы (1)


Json.NET в настоящее время не поддерживает строгий анализ имен свойств JSON.

Внутренне JToken.Parse() создает JsonTextReader для анализа строки JSON, и она появляется возможность JsonTextReader анализировать имена свойств без кавычек в настоящее время не может быть отключена.

При итерации файла JSON через JsonTextReader.Read() метод JsonTextReader.ParseProperty() используется для анализа имен свойств:

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

И, как видно из справочника, 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

Как видите, нет возможности настроить средство чтения для выдачи исключения для свойств без двойных кавычек.

В качестве обходного пути текущий Json лицензия позволяет копировать и изменять. Таким образом, вы сможете создать свой собственный 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 широко использует утилиты из _ 13_. Вы должны выделить пару дней на создание минимальной копии необходимых утилит.

В качестве альтернативы вы можете создать собственную версию Json.NET, собрать ее самостоятельно и использовать вместо официальной версии. В любом случае не забудьте разветвить исходный код той версии, которую хотите использовать:

Выберите правильную версию

В качестве альтернативы созданию собственного анализатора вы можете предварительно обработать свой JSON с помощью _ 14_, чтобы обеспечить строгое соответствие стандарту 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'}")

Ссылки по теме:

person dbc    schedule 14.11.2018