Як переконатися, що рядок є дійсним JSON за допомогою JSON.NET


147

У мене сира струна. Я просто хочу перевірити, чи строка дійсна JSON чи ні. Я використовую JSON.NET.

Відповіді:


207

Через код:

Ваша найкраща ставка - використовувати синтаксичний розбір усередині try-catchі вилучити виняток у разі невдалого розбору. (Я не знаю жодного TryParseметоду) .

(Використання JSON.Net)

Найпростішим способом було б Parseвикористання рядка JToken.Parse, а також перевірити, чи починається рядок з {або [закінчується відповідно }або ]відповідно (додано з цієї відповіді ) :

private static bool IsValidJson(string strInput)
{
    if (string.IsNullOrWhiteSpace(stringValue)) { return false;}
    strInput = strInput.Trim();
    if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
        (strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
    {
        try
        {
            var obj = JToken.Parse(strInput);
            return true;
        }
        catch (JsonReaderException jex)
        {
            //Exception in parsing json
            Console.WriteLine(jex.Message);
            return false;
        }
        catch (Exception ex) //some other exception
        {
            Console.WriteLine(ex.ToString());
            return false;
        }
    }
    else
    {
        return false;
    }
}

Причина додавання перевірок на {або [тощо базувалася на тому, що JToken.Parseби розбирати значення, такі як "1234"або "'a string'"як дійсний маркер. Інший варіант міг би використовувати як JObject.Parseі JArray.Parseв розборі і подивитися , якщо хто - небудь з них вдасться, але я вважаю , перевірка {}і []має бути простіше. (Дякуємо @RhinoDevel за вказівку на це)

Без JSON.Net

Ви можете використовувати .Net Framework 4.5 Простір імен System.Json , як-от:

string jsonString = "someString";
try
{
    var tmpObj = JsonValue.Parse(jsonString);
}
catch (FormatException fex)
{
    //Invalid json format
    Console.WriteLine(fex);
}
catch (Exception ex) //some other exception
{
    Console.WriteLine(ex.ToString());
}

(Але вам доведеться встановити System.Jsonчерез менеджер пакунків Nuget за допомогою команди: PM> Install-Package System.Json -Version 4.0.20126.16343на консолі диспетчера пакунків) (взято звідси )

Некодовий спосіб:

Зазвичай, коли є невелика рядок json і ви намагаєтесь знайти помилку в рядку json, я особисто вважаю за краще використовувати доступні он-лайн інструменти. Що я зазвичай роблю:

  • Вставте рядок JSON у JSONLint Валідатор JSON і подивіться, чи є його дійсним JSON.
  • Пізніше скопіюйте правильний JSON на http://json2csharp.com/ та згенеруйте для нього клас шаблонів, а потім де-серіалізуйте його за допомогою JSON.Net.

3
Як це можна зробити під час виконання. Я не хочу використовувати спробу лову для перевірки
user960567

1
Ви можете створити схему для свого JSON і пізніше перевірити цю схему, див .: Json.NET 3.5 Beta 2 - Перевірка схеми JSON
Хабіб

1
Будь-який спосіб зробити це без пробного блоку? Я не використовую пробні блоки, якщо я маю справу з невідомим. Я шукаю щось на зразок JsonConvert.TryDeserializeObject. Оперативні спроби улову - це просто поганий код.
Йорданія

1
Використання Json.NET: Це НЕ згенерує виняток: JToken.Parse("1234")! Можливо, буде гарною ідеєю спочатку перевірити, чи починається рядок з [або {. Ще одна альтернатива - використання JObject.Parse()та JArray.Parse().
RhinoDevel

1
JToken.Parse("{a:1}")ніяк НЕ кидати виняток , навіть якщо це є неприпустимим JSON - aповинні бути вказані ( stackoverflow.com/q/949449/3116322 )
Ande

31

Використовуйте JContainer.Parse(str)метод, щоб перевірити, чи str є дійсним Json. Якщо це кидає виняток, то це не дійсний Json.

JObject.Parse- Може використовуватися для перевірки, чи є рядок дійсним об'єктом Json
JArray.Parse- Може використовуватися для перевірки, чи є строка дійсною масивом Json
JContainer.Parse- Може використовуватися для перевірки як об'єкта Json, так і масиву


17
Замість JContainer правильніше використовувати тип JToken, оскільки метод Parse () оголошений на цьому рівні
Денис Моря

6
Я припускаю, що ви говорите про JSON.Net: JContainer працює не так, оскільки він не викине виключення у всіх розшукуваних випадках. Приклад: JContainer.Parse("1234");.
RhinoDevel

Неправильна відповідь, JContainer.Parse працює над чим завгодно
Інструментарій

19

Спираючись на відповідь Хабіба, ви можете написати метод розширення:

public static bool ValidateJSON(this string s)
{
    try
    {
        JToken.Parse(s);
        return true;
    }
    catch (JsonReaderException ex)
    {
        Trace.WriteLine(ex);
        return false;
    }
}

Що потім можна використовувати так:

if(stringObject.ValidateJSON())
{
    // Valid JSON!
}

1
JToken.Parse(s);повертається trueнавіть якщоJToken.Parse(123);
Make Makeluv

2
Повернення trueцього недійсного JSON:{A:{"B": 1}}
Мехді Дехгані

Хороший метод розширення, щоб мати :) Хоча, мабуть, його краще назвати "IsValidJson".
Младен Б.

11

Просто щоб додати щось у відповідь @ Habib, ви також можете перевірити, чи вказано JSON від правильного типу:

public static bool IsValidJson<T>(this string strInput)
{
    strInput = strInput.Trim();
    if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
        (strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
    {
        try
        {
            var obj = JsonConvert.DeserializeObject<T>(strInput);
            return true;
        }
        catch // not valid
        {             
            return false;
        }
    }
    else
    {
        return false;
    }
}

7

Я виявив, що JToken.Parse неправильно аналізує недійсний JSON, такий як:

{
"Id" : , 
"Status" : 2
}

Вставте рядок JSON в http://jsonlint.com/ - вона недійсна.

Тому я використовую:

public static bool IsValidJson(this string input)
{
    input = input.Trim();
    if ((input.StartsWith("{") && input.EndsWith("}")) || //For object
        (input.StartsWith("[") && input.EndsWith("]"))) //For array
    {
        try
        {
            //parse the input into a JObject
            var jObject = JObject.Parse(input);

            foreach(var jo in jObject)
            {
                string name = jo.Key;
                JToken value = jo.Value;

                //if the element has a missing value, it will be Undefined - this is invalid
                if (value.Type == JTokenType.Undefined)
                {
                    return false;
                }
            }
        }
        catch (JsonReaderException jex)
        {
            //Exception in parsing json
            Console.WriteLine(jex.Message);
            return false;
        }
        catch (Exception ex) //some other exception
        {
            Console.WriteLine(ex.ToString());
            return false;
        }
    }
    else
    {
        return false;
    }

    return true;
}

Це недійсний рядок JSON ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf ось документація стандарту JSON Standard ECMA, і в пункті 5 Значення JSON ви можете побачити, що значення може приймати нуль як значення . Тож його просто помилка у перекладача jsonlint
Домінік Лембергер

4
Домінік, значення JSON згідно з моїм прочитанням специфікації, яку ви зв'язали, має мати деякий маркер, при цьому буквальний нульовий текст представляє нульове значення. Дійсні значення - "об'єкт, масив, число, рядок, істина, помилка чи нуль" відповідно до специфікації, на яку ви посилалися. AFAICS немає дійсного значення без знака значення.
Кіртлендер

Це виглядає так, що це буде добре з недійсним JSON, який виглядає приблизно так{ name : "l am invalid JSON" }
Jon49,

2

⚠️ Альтернативна опція не використовується JSON.Net ⚠️

Для .Net Core / .Net 5 ( при попередньому перегляді на момент написання цього тексту ) також можна використовувати System.Text.Jsonпростір імен та проаналізувати за допомогою JsonDocument. Приклад - метод розширення на основі операцій з простором імен:

public static bool IsJsonValid(this string txt)
{
    try { return JsonDocument.Parse(txt) != null; } catch {}

    return false;
}

1

Щодо відповіді Тома Бука; Натомість я придумав таке:

public bool ValidateJSON(string s)
{
    try
    {
        JToken.Parse(s);
        return true;
    }
    catch (JsonReaderException ex)
    {
        Trace.WriteLine(ex);
        return false;
    }
}

З використанням наступного:

if (ValidateJSON(strMsg))
{
    var newGroup = DeserializeGroup(strMsg);
}

3
Це не нове - ви зробили метод розширення не метод розширення. Відповідь Тома Біка вже може досягти того, що вам потрібно (загалом, я б також нахмурився додавати такі методи розширення string, але ця відповідь справді повинна бути а) не бути тут або б) сказати "я використав відповідь Тома Бука " без this, тобто без його подовжуючого елемента) - і ця відповідь і посилання один мають однакову стислість і слабкі сторони. Якщо ви маєте зробити це, просто поставте коментар до іншої відповіді.
Рубен Бартелинк

1

JToken.Typeдоступний після успішного розбору. Це може бути використане для усунення частини преамбули у відповідях вище та надання розуміння для більш тонкого контролю результату. Повністю недійсний вклад (наприклад, "{----}".IsValidJson();все одно буде винятком).

    public static bool IsValidJson(this string src)
    {
        try
        {
            var asToken = JToken.Parse(src);
            return asToken.Type == JTokenType.Object || asToken.Type == JTokenType.Array;
        }
        catch (Exception)  // Typically a JsonReaderException exception if you want to specify.
        {
            return false;
        }
    }

Посилання Json.Net для JToken.Type: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm


0

Цей метод не вимагає зовнішніх бібліотек

using System.Web.Script.Serialization;
bool IsValidJson(string json)
    {
        try {
            var serializer = new JavaScriptSerializer();
            dynamic result = serializer.DeserializeObject(json);
            return true;
        } catch { return false; }
    }

0

Ось метод TryParse розширення на основі відповіді Хабіба:

public static bool TryParse(this string strInput, out JToken output)
{
    if (String.IsNullOrWhiteSpace(strInput))
    {
        output = null;
        return false;
    }
    strInput = strInput.Trim();
    if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
        (strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
    {
        try
        {
            output = JToken.Parse(strInput);
            return true;
        }
        catch (JsonReaderException jex)
        {
            //Exception in parsing json
            //optional: LogError(jex);
            output = null;
            return false;
        }
        catch (Exception ex) //some other exception
        {
            //optional: LogError(ex);
            output = null;
            return false;
        }
    }
    else
    {
        output = null;
        return false;
    }
}

Використання:

JToken jToken;
if (strJson.TryParse(out jToken))
{
    // work with jToken
}
else
{
    // not valid json
}

0

Я використовую цей:

  internal static bool IsValidJson(string data)
  {
     data = data.Trim();
     try
     {
        if (data.StartsWith("{") && data.EndsWith("}"))
        {
           JToken.Parse(data);
        }
        else if (data.StartsWith("[") && data.EndsWith("]"))
        {
           JArray.Parse(data);
        }
        else
        {
           return false;
        }
        return true;
     }
     catch
     {
        return false;
     }
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.