Edited at

[C#]DataContractJsonSerializerのJsonを読みやすく整形する

More than 1 year has passed since last update.


これはなに

C#でDataContractJsonSerializerを使いJsonを出力すると、1行になって出力されるので、

最低限見やすいように整形するコードです。


コード


json.cs

public class Json

{
public static string Serialize(object target)
{
using (var stream = new MemoryStream())
{
var serializer = new DataContractJsonSerializer(target.GetType());
serializer.WriteObject(stream, target);
return Encoding.UTF8.GetString(stream.ToArray());
}
}

//2017/04/17 StringBuilder版
public static string ToReadable(string json)
{
if (string.IsNullOrWhiteSpace(json)) return json;
int i = 0;
int indent = 0;
int quoteCount = 0;
int position = -1;
var sb = new StringBuilder();
int lastindex = 0;
while (true)
{
if (i > 0 && json[i] == '"' && json[i - 1] != '\\') quoteCount++;

if (quoteCount % 2 == 0) //is not value(quoted)
{
if (json[i] == '{' || json[i] == '[')
{
indent++;
position = 1;
}
else if (json[i] == '}' || json[i] == ']')
{
indent--;
position = 0;
}
else if (json.Length > i && json[i] == ',' && json[i + 1] == '"')
{
position = 1;
}
if (position >= 0)
{
sb.AppendLine(json.Substring(lastindex, i + position - lastindex));
sb.Append(new string(' ', indent * 4));
lastindex = i + position;
position = -1;
}
}

i++;
if (json.Length <= i)
{
sb.Append(json.Substring(lastindex));
break;
}

}
return sb.ToString();
}

public static string ToReadableOld(string json)
{
if (string.IsNullOrWhiteSpace(json)) return json;
int i = 0;
int indent = 0;
int quoteCount = 0;
int position = -1;
string indentStr = "\n";
while (true)
{
if (i > 0 && json[i] == '"' && json[i - 1] != '\\') quoteCount++;

if (quoteCount % 2 == 0) //is not value(quoted)
{
if (json[i] == '{' || json[i] == '[')
{
indent++;
position = 1;
}
else if (json[i] == '}' || json[i] == ']')
{
indent--;
position = 0;
}
else if (json.Length > i && json[i] == ',' && json[i + 1] == '"')
{
position = 1;
}
if (position >= 0)
{
indentStr = "\n" + new string(' ', indent * 4);
json = json.Substring(0, i + position) + indentStr + json.Substring(i + position);
i += indentStr.Length - position;
position = -1;
}
}

i++;
if (json.Length <= i) break;
}
return json;
}

public static T Deserialize<T>(string json)
{
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(stream);
}
}

public static object Deserialize(Type type, string json)
{
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
var serializer = new DataContractJsonSerializer(type);
return serializer.ReadObject(stream);
}
}
}



サンプル


sample.cs

public class sample

{
public int num { get; set; } = 100;
public string str { get; set; } = "abc";
public List<string> list { get; set; } = new List<string> { "A", "B", "C", "Escape:", "{", "}", "\"", "[", "]" };
}

private void test()
{
var s = new sample();

var json1 = Json.Serialize(s);
Debug.WriteLine(json1);
//{"list":["A","B","C","Escape:","{","}","\"","[","]"],"num":100,"str":"abc"}

var json2 = Json.ToReadable(json1);
Debug.WriteLine(json2);
//{
// "list":[
// "A",
// "B",
// "C",
// "Escape:",
// "{",
// "}",
// "\"",
// "[",
// "]"
// ],
// "num":100,
// "str":"abc"
//}

var s1 = Json.Deserialize<sample>(json1);
var s2 = Json.Deserialize<sample>(json2);
Debug.WriteLine(Json.Serialize(s1) == Json.Serialize(s2));
//True

}



おわりに

とりあえず今のところ使っていて問題は起きていませんが、

ご指摘あればどんどんお願いします。


追記 2017/04/17

大きいJsonを処理した際あまりに遅かったため、StringBuilderを使用したコードに

書き換えました。ToReadableが新しいコードでToReadableOldが古いコードです。

改行が\nから\r\nになっています。


test.cs

var j = Json.Serializer.Serialize(s);

var sw = new System.Diagnostics.Stopwatch();
sw.Start();
var t1 = Json.Serializer.ToReadableOld(j);
Debug.Log("Old:" + sw.ElapsedMilliseconds.ToString() + "ms");

sw.Restart();
var t2 = Json.Serializer.ToReadable(j).Replace("\r","");
Debug.Log("New:" + sw.ElapsedMilliseconds.ToString() + "ms");

Debug.Log("Old == New:" + (t1 == t2).ToString());
//Old:140653ms
//New:31ms
//Old == New:True