Пользовательское форматирование JSON в зависимости от количества свойств - PullRequest
0 голосов
/ 09 октября 2019

Я ищу способ разбить строку JSON на несколько строк после сериализации, вставляя новую строку после каждого свойства Nth.

Например, у меня есть этот класс:

public class Obj
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public string[] Property3 { get; set; }
    public string Property4 { get; set; }
    public string Property5 { get; set; }
    public string Property6 { get; set; }
    public TimeSpan Time { get; set; }
    public string Property7 { get; set; }
    public string Property8 { get; set; }
    public string Property9 { get; set; }
    public string Property10 { get; set; }
    public string[] Property11 { get; set; }
}

Инициализируется примерно так:

var root = new Obj
    {
        Property1 = "value1",
        Property2 = "value2",
        Property3 = new[] {"test", "test1", "test3"},
        Property4 = "value4",
        Property5 = "value5",
        Property6 = "value6",
        Time = TimeSpan.FromSeconds(13),
        Property7 = "value7",
        Property8 = "value8",
        Property9 = "value9",
        Property10 = "value10",
        Property11 = new string[] {"asdf", "basdf"}
    };

Когда я вызываю JsonConvert.SerializeObject(root), он печатает:

{"Property1":"value1","Property2":"value2","Property3":["test","test1","test3"],"Property4":"value4","Property5":"value5","Property6":"value6","Time":"00:00:13","Property7":"value7","Property8":"value8","Property9":"value9","Property10":"value10","Property11":["asdf","basdf"]}

Я хотел бы добавить новую строку один раз после каждого N-го свойства. Скажем, каждое третье свойство.

Я попробовал что-то вроде этого:

public static string ReplaceEveryNth(string fullString, string pattern, int n)
{
    if (n < 1) { return fullString; }

    var index = 1;
    return Regex.Replace(fullString, pattern, m =>
    {
        return (index++ % n == 0) ? m.Value + Environment.NewLine : m.Value;
    });
}

и назвал его так, чтобы соответствовать парам ключ-значение в строке JSON:

var replaced = ReplaceEveryNth(json, "(\".*?\":\".*?\"),", 3);

Теперь это работает для простых свойств. Но когда я начинаю вводить типы, такие как массивы, регулярное выражение становится более сложным.

Мне интересно, существует ли более простой подход.

Ответы [ 2 ]

2 голосов
/ 09 октября 2019

Я не уверен, что это именно то, что вы ищете, но вы можете попробовать реализовать пользовательский JsonWriter для вставки новой строки перед каждым N-м именем свойства (при условии, что вы используете Json.Net ):

public class CustomJsonWriter : JsonTextWriter
{
    public int N { get; set; }
    private int propertyCount = 0;

    public CustomJsonWriter(TextWriter textWriter, int n) : base(textWriter)
    {
        N = n;
    }

    public override void WritePropertyName(string name, bool escape)
    {
        if (propertyCount > 0 && propertyCount % N == 0)
            WriteWhitespace(Environment.NewLine);

        base.WritePropertyName(name, escape);
        propertyCount++;
    }
}

Вспомогательный метод упрощает использование:

public static string SerializeWithCustomFormatting(object obj, int n)
{
    using (TextWriter sw = new StringWriter())
    using (JsonWriter writer = new CustomJsonWriter(sw, n))
    {
        JsonSerializer ser = new JsonSerializer();
        ser.Serialize(writer, obj);
        return sw.ToString();
    }
}

Тогда вы можете сделать:

string json = SerializeWithCustomFormatting(root, 3);

В вашем примере это выдает следующий результат:

{"Property1":"value1","Property2":"value2","Property3":["test","test1","test3"]
,"Property4":"value4","Property5":"value5","Property6":"value6"
,"Time":"00:00:13","Property7":"value7","Property8":"value8"
,"Property9":"value9","Property10":"value10","Property11":["asdf","basdf"]}

Fiddle: https://dotnetfiddle.net/gG8az2

2 голосов
/ 09 октября 2019

Подойдет ли вам полностью с отступом json?

 var json = JsonConvert.SerializeObject(o, new JsonSerializerSettings
            {
                Formatting = Formatting.Indented
            });

Обновление

Поскольку полностью с отступом json недостаточно, вы можете попробовать собственный конвертер.

Результат

{"Property1":"value1","Property2":"value2","Property3":["test","test1","test3"]
,"Property4":"value4","Property5":"value5","Property6":"value6"
,"Time":"00:00:13","Property7":"value7","Property8":"value8"
,"Property9":"value9","Property10":"value10","Property11":["asdf","basdf"]
}

Преобразователь

public class CustomLineBreakerConverter : JsonConverter
{
  private readonly uint n;
  private uint i = 1;

  public CustomLineBreakerConverter(uint n) { this.n = n; }

  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  {
    // Scaffolding from https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm

    // Please note this will not work recursively (only the top level will be have the new lines
    JToken t = JToken.FromObject(value);

    if (t.Type != JTokenType.Object)
    {
      t.WriteTo(writer);
    }
    else
    {
      JObject o = (JObject)t;
      var properties = o.Properties();
      writer.WriteStartObject();
      foreach( var p in properties)
      {
        p.WriteTo(writer);
        if (i++ % n == 0)
        {
          writer.WriteWhitespace("\r\n");  // This will write a new line after the property even if no more properties
        }
      }
      writer.WriteEndObject();
    }
  }
  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
     => throw new NotImplementedException("This converter is meant only for writing");
  public override bool CanConvert(Type objectType) => true;
}

Тестовый код

var o = new
{
    Property1 = "value1",
    Property2 = "value2",
    Property3 = new[] { "test", "test1", "test3" },
    Property4 = "value4",
    Property5 = "value5",
    Property6 = "value6",
    Time = TimeSpan.FromSeconds(13),
    Property7 = "value7",
    Property8 = "value8",
    Property9 = "value9",
    Property10 = "value10",
    Property11 = new string[] { "asdf", "basdf" }
};

var json = JsonConvert.SerializeObject(o, new JsonSerializerSettings
{
    Formatting = Formatting.None,
    Converters = new List<JsonConverter>() { new CustomLineBreakerConverter(3) }
});

Console.WriteLine(json);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...