Як мені відформатувати JSON у .NET за допомогою C #?


256

Я використовую .NET JSON парсер і хотів би серіалізувати свій конфігураційний файл, щоб він був читабельним. Тож замість:

{"blah":"v", "blah2":"v2"}

Мені б хотілося чогось приємного, як:

{
    "blah":"v", 
    "blah2":"v2"
}

Мій код приблизно такий:

using System.Web.Script.Serialization; 

var ser = new JavaScriptSerializer();
configSz = ser.Serialize(config);
using (var f = (TextWriter)File.CreateText(configFn))
{
    f.WriteLine(configSz);
    f.Close();
}

Відповіді:


257

Вам буде важко досягти цього за допомогою JavaScriptSerializer.

Спробуйте JSON.Net .

З незначними модифікаціями прикладу JSON.Net

using System;
using Newtonsoft.Json;

namespace JsonPrettyPrint
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Product product = new Product
                {
                    Name = "Apple",
                    Expiry = new DateTime(2008, 12, 28),
                    Price = 3.99M,
                    Sizes = new[] { "Small", "Medium", "Large" }
                };

            string json = JsonConvert.SerializeObject(product, Formatting.Indented);
            Console.WriteLine(json);

            Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);
        }
    }

    internal class Product
    {
        public String[] Sizes { get; set; }
        public decimal Price { get; set; }
        public DateTime Expiry { get; set; }
        public string Name { get; set; }
    }
}

Результати

{
  "Sizes": [
    "Small",
    "Medium",
    "Large"
  ],
  "Price": 3.99,
  "Expiry": "\/Date(1230447600000-0700)\/",
  "Name": "Apple"
}

Документація: серіалізація об'єкта


Також є приклад форматування виходу json у своєму блозі james.newtonking.com/archive/2008/10/16/…
R0MANARMY

15
@Brad Він показав абсолютно той самий код, але використовуючи модель
Mia

Тож ідея є просто Formatting.Indented
FindOutIslamNow

Цей спосіб також рятує від помилок формату JSON.
Аншуман Гель

172

Коротший зразок коду для бібліотеки Json.Net

private static string FormatJson(string json)
{
    dynamic parsedJson = JsonConvert.DeserializeObject(json);
    return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
}

1
Ви можете зробити це на крок далі та створити метод розширення; оприлюднити його та змінити підпис на FormatJson (цей рядок json)
bdwakefield

129

Якщо у вас є рядок JSON і ви хочете "вподобати" її, але не хочете її серіалізувати до відомого типу C #, то наступне виконує фокус (використовуючи JSON.NET):

using System;
using System.IO;
using Newtonsoft.Json;

class JsonUtil
{
    public static string JsonPrettify(string json)
    {
        using (var stringReader = new StringReader(json))
        using (var stringWriter = new StringWriter())
        {
            var jsonReader = new JsonTextReader(stringReader);
            var jsonWriter = new JsonTextWriter(stringWriter) { Formatting = Formatting.Indented };
            jsonWriter.WriteToken(jsonReader);
            return stringWriter.ToString();
        }
    }
}

6
Що стосується лише оздоблення струни Json, це набагато правильне рішення, ніж інші ...
Jens Marchewka

2
Наступні випадки використання не вдасться: JsonPrettify("null")таJsonPrettify("\"string\"")
Екеву

1
Дякую @Ekevoo, я повернув її до своєї попередньої версії!
Duncan Smart

@DuncanSmart Я люблю це! Ця версія створює набагато менше тимчасових об'єктів. Я думаю, що це краще, ніж той, кого я критикував, навіть якщо ці випадки використання спрацювали.
Екеву

97

Найкоротша версія для покращення існуючого JSON: (редагувати: використовуючи JSON.net)

JToken.Parse("mystring").ToString()

Вхід:

{"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }}

Вихід:

{
  "menu": {
    "id": "file",
    "value": "File",
    "popup": {
      "menuitem": [
        {
          "value": "New",
          "onclick": "CreateNewDoc()"
        },
        {
          "value": "Open",
          "onclick": "OpenDoc()"
        },
        {
          "value": "Close",
          "onclick": "CloseDoc()"
        }
      ]
    }
  }
}

Щоб красиво роздрукувати об’єкт:

JToken.FromObject(myObject).ToString()

4
Це працює навіть не знаючи заздалегідь структуру json. І це найкоротший відповідь тут.
foresightyj

1
Це працює, але лише якщо об’єкт json не є масивом. Якщо ви знаєте, що це буде масив, ви можете замість цього JArray.Parse.
Лука Z

3
Ах, хороший момент, дякую. Я оновив свою відповідь, яку потрібно використовувати JTokenзамість JObject. Це працює з об'єктами або масивами, оскільки JTokenце клас предків для обох JObjectі JArray.
ашербер

Велике спасибі, чоловіче, що я витратив близько 2 годин, щоб дійти до цього рішення ... Не уявляю свого життя без @stackoverflow ...
Рудреша Парамешаппа

Мені дуже подобається ця відповідь над іншими відповідями. Короткий код та дієвий. Дякую
Марк Руссел

47

Oneliner з використанням Newtonsoft.Json.Linq:

string prettyJson = JToken.Parse(uglyJsonString).ToString(Formatting.Indented);

Я погоджуюсь, що це найпростіший API для форматування JSON за допомогою Newtonsoft
Ethan Wu

2
Не вдалося знайти це в Newtonsoft.Json ... можливо, у мене є старша версія.
cslotty

2
Він знаходиться в просторі імен NewtonSoft.Json.Linq. Я це знаю лише тому, що я теж пішов на пошуки.
Капітан Кенпачі

12

Ви можете використовувати наступний стандартний метод для форматування Json

JsonReaderWriterFactory.CreateJsonWriter (Потік потоку, Кодування кодування, bool володієStream, відступ bool, string indentChars)

Встановити лише "indent == true"

Спробуйте щось подібне

    public readonly DataContractJsonSerializerSettings Settings = 
            new DataContractJsonSerializerSettings
            { UseSimpleDictionaryFormat = true };

    public void Keep<TValue>(TValue item, string path)
    {
        try
        {
            using (var stream = File.Open(path, FileMode.Create))
            {
                //var currentCulture = Thread.CurrentThread.CurrentCulture;
                //Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                try
                {
                    using (var writer = JsonReaderWriterFactory.CreateJsonWriter(
                        stream, Encoding.UTF8, true, true, "  "))
                    {
                        var serializer = new DataContractJsonSerializer(type, Settings);
                        serializer.WriteObject(writer, item);
                        writer.Flush();
                    }
                }
                catch (Exception exception)
                {
                    Debug.WriteLine(exception.ToString());
                }
                finally
                {
                    //Thread.CurrentThread.CurrentCulture = currentCulture;
                }
            }
        }
        catch (Exception exception)
        {
            Debug.WriteLine(exception.ToString());
        }
    }

Зверніть свою увагу на лінії

    var currentCulture = Thread.CurrentThread.CurrentCulture;
    Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
    ....
    Thread.CurrentThread.CurrentCulture = currentCulture;

Для деяких видів xml-серіалізаторів слід використовувати InvariantCulture, щоб уникнути виключення під час десеріалізації на комп'ютерах з різними регіональними налаштуваннями. Наприклад, недійсний формат подвійного або DateTime іноді їх викликає .

Для десеріалізації

    public TValue Revive<TValue>(string path, params object[] constructorArgs)
    {
        try
        {
            using (var stream = File.OpenRead(path))
            {
                //var currentCulture = Thread.CurrentThread.CurrentCulture;
                //Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                try
                {
                    var serializer = new DataContractJsonSerializer(type, Settings);
                    var item = (TValue) serializer.ReadObject(stream);
                    if (Equals(item, null)) throw new Exception();
                    return item;
                }
                catch (Exception exception)
                {
                    Debug.WriteLine(exception.ToString());
                    return (TValue) Activator.CreateInstance(type, constructorArgs);
                }
                finally
                {
                    //Thread.CurrentThread.CurrentCulture = currentCulture;
                }
            }
        }
        catch
        {
            return (TValue) Activator.CreateInstance(typeof (TValue), constructorArgs);
        }
    }

Дякую!


Вітаю, @Makeman, ти коли-небудь відтворював помилки серіалізації, спричинені різними культурами? Схоже, що конверсії XmlJsonWriter / Reader всі культури інваріантні.
Олександр Іваницький

Привіт, я не впевнений у XmlJsonWriter / Reader, але DataContractJsonSerializer використовує Thread.CurrentThread.CurrentCulture. Помилки можуть виникнути, коли дані були серіалізовані на апараті A, але десеріалізовані на B з іншими регіональними налаштуваннями.
Макеман

Я декомпілював DataContractJsonSerializerв зборах System.Runtime.Serialization v.4.0.0.0, явного використання цього немає CurrentCulture. Єдине використання культури - CultureInfo.InvariantCultureце базовий клас XmlObjectSerializer, внутрішній метод TryAddLineInfo.
Олександр Іваницький

Тож, може, це моя помилка. Я перевірю це пізніше. Можливо, я екстраполюю це питання культури від впровадження іншого серіалізатора.
Макеман

1
Я відредагував оригінальну відповідь. Здається, що серіалізатори DataContract - це культура, незалежна від культури, але вам слід заощадити увагу, щоб уникнути специфічних для культури помилок під час серіалізації іншими видами серіалізаторів. :)
Makeman

6

Все це можна зробити одним простим рядком:

string jsonString = JsonConvert.SerializeObject(yourObject, Formatting.Indented);

1
Не забудьте додати "за допомогою Newtonsoft.Json"
Ebube

найкраще відповісти мій друг.
RogerEdward

5

Ось рішення з використанням бібліотеки Microsoft System.Text.Json :

static string FormatJsonText(string jsonString)
{
    using var doc = JsonDocument.Parse(
        jsonString,
        new JsonDocumentOptions
        {
            AllowTrailingCommas = true
        }
    );
    MemoryStream memoryStream = new MemoryStream();
    using (
        var utf8JsonWriter = new Utf8JsonWriter(
            memoryStream,
            new JsonWriterOptions
            {
                Indented = true
            }
        )
    )
    {
        doc.WriteTo(utf8JsonWriter);
    }
    return new System.Text.UTF8Encoding()
        .GetString(memoryStream.ToArray());
}

Це хороше рішення для тих, хто не може придбати додатковий пакет. Добре працює.
Марк Т

2

Спершу я хотів додати коментар під публікацією Duncan Smart, але, на жаль, ще не маю достатньої репутації, щоб залишати коментарі. Тому я спробую це тут.

Я просто хочу попередити про побічні ефекти.

JsonTextReader внутрішньо розбирає json на введений JTokens, а потім послідовно повертає їх назад.

Наприклад, якщо ваш оригінальний JSON був

 { "double":0.00002, "date":"\/Date(1198908717056)\/"}

Після гарнітури ви отримаєте

{ 
    "double":2E-05,
    "date": "2007-12-29T06:11:57.056Z"
}

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


Тут є велика дискусія щодо цієї деталі ... github.com/JamesNK/Newtonsoft.Json/isissue/862 Цікаво, як ця деталь розвивалася. Я дізнався щось нове про свій основний аналізатор json - Дякую за Ваш коментар.
Sql Surfer

2

Використовуючи System.Text.Jsonнабір JsonSerializerOptions.WriteIndented = true:

JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize<Type>(object, options);


0

Це працювало для мене. Якщо хтось шукає версію VB.NET

@imports System
@imports System.IO
@imports Newtonsoft.Json

Public Shared Function JsonPrettify(ByVal json As String) As String
  Using stringReader = New StringReader(json)

    Using stringWriter = New StringWriter()
      Dim jsonReader = New JsonTextReader(stringReader)
      Dim jsonWriter = New JsonTextWriter(stringWriter) With {
          .Formatting = Formatting.Indented
      }
      jsonWriter.WriteToken(jsonReader)
      Return stringWriter.ToString()
    End Using
  End Using
End Function

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.