7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-04-06

#これはなに
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
7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?