基于属性数量的自定义 JSON 格式
Posted
技术标签:
【中文标题】基于属性数量的自定义 JSON 格式【英文标题】:Custom JSON formatting based on number of properties 【发布时间】:2020-02-06 05:13:36 【问题描述】:我正在寻找一种在序列化后将 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 个属性之后添加一个新行。假设每 3 个属性。
我尝试过这样的事情:
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);
现在,这适用于简单的属性。但是当我开始引入像数组这样的类型时,Regex 变得更加复杂。
我想知道是否有更简单的方法。
【问题讨论】:
您是否只需要每个 x 属性的新行?或者你会接受完全缩进的 JSON 输出吗?您可以将第二个参数传递给 SerializeObject 方法以指示您想要格式化输出。 newtonsoft.com/json/help/html/… 正如问题所述,我想根据计数缩进 【参考方案1】:我不确定这是否正是您要寻找的,但您可以尝试实现自定义 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"]
小提琴:https://dotnetfiddle.net/gG8az2
【讨论】:
这是完美的。WritePropertyName
是我要找的那个。
很高兴我能帮上忙。【参考方案2】:
完全缩进的 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);
【讨论】:
我想在每个属性后缩进一次,而不是每个属性。以上是关于基于属性数量的自定义 JSON 格式的主要内容,如果未能解决你的问题,请参考以下文章