Simple JSON .NET formatter
StringWalker class:
public class StringWalker { private readonly string _s; public int Index { get; private set; } public bool IsEscaped { get; private set; } public char CurrentChar { get; private set; } public StringWalker(string s) { _s = s; this.Index = -1; } public bool MoveNext() { if (this.Index == _s.Length - 1) return false; if (IsEscaped == false) IsEscaped = CurrentChar == '\\'; else IsEscaped = false; this.Index++; CurrentChar = _s[Index]; return true; } };
IndentWriter class:
public class IndentWriter { private readonly StringBuilder _result = new StringBuilder(); private int _indentLevel; public void Indent() { _indentLevel++; } public void UnIndent() { if (_indentLevel > 0) _indentLevel--; } public void WriteLine(string line) { _result.AppendLine(CreateIndent() + line); } private string CreateIndent() { StringBuilder indent = new StringBuilder(); for (int i = 0; i < _indentLevel; i++) indent.Append(" "); return indent.ToString(); } public override string ToString() { return _result.ToString(); } };
JSON formatter class:
public class JsonFormatter { private readonly StringWalker _walker; private readonly IndentWriter _writer = new IndentWriter(); private readonly StringBuilder _currentLine = new StringBuilder(); private bool _quoted; public JsonFormatter(string json) { _walker = new StringWalker(json); ResetLine(); } public void ResetLine() { _currentLine.Length = 0; } public string Format() { while (MoveNextChar()) { if (this._quoted == false && this.IsOpenBracket()) { this.WriteCurrentLine(); this.AddCharToLine(); this.WriteCurrentLine(); _writer.Indent(); } else if (this._quoted == false && this.IsCloseBracket()) { this.WriteCurrentLine(); _writer.UnIndent(); this.AddCharToLine(); } else if (this._quoted == false && this.IsColon()) { this.AddCharToLine(); this.WriteCurrentLine(); } else { AddCharToLine(); } } this.WriteCurrentLine(); return _writer.ToString(); } private bool MoveNextChar() { bool success = _walker.MoveNext(); if (this.IsApostrophe()) { this._quoted = !_quoted; } return success; } public bool IsApostrophe() { return this._walker.CurrentChar == '"' && this._walker.IsEscaped == false; } public bool IsOpenBracket() { return this._walker.CurrentChar == '{' || this._walker.CurrentChar == '['; } public bool IsCloseBracket() { return this._walker.CurrentChar == '}' || this._walker.CurrentChar == ']'; } public bool IsColon() { return this._walker.CurrentChar == ','; } private void AddCharToLine() { this._currentLine.Append(_walker.CurrentChar); } private void WriteCurrentLine() { string line = this._currentLine.ToString().Trim(); if (line.Length > 0) { _writer.WriteLine(line); } this.ResetLine(); } };
Few samples:
Console.WriteLine(new JsonFormatter( @"{""parameter"" : ""value"" , { ""parameter2"" : ""value2"" },{ ""parameter3"" : ""value3"" } }").Format()); Console.WriteLine(new JsonFormatter( @"{""parameter"":[""value1"",""value2"",""value3""] }").Format()); Console.WriteLine(new JsonFormatter( @"{""parameter"": ""value with {brackets}"" }").Format()); Console.WriteLine(new JsonFormatter( @"{ ""hello"" : ""value with quotes \""{brackets} and back slash: \\"" }").Format());
…and results:
{ "parameter" : "value" , { "parameter2" : "value2" }, { "parameter3" : "value3" } } { "parameter": [ "value1", "value2", "value3" ] } { "parameter": "value with {brackets}" } { "hello" : "value with quotes \"{brackets} and back slash: \\" }
July 13th, 2014 at 17:23
From all the frameworks I’d tried, like newtonking, jayrock, json.net, and many others, this is the simplest solution ever. Thank you for this article.
April 13th, 2015 at 22:51
Hey – I am really glad to find this. great job!
July 21st, 2015 at 12:52
Thank you very simple and elegant solution
Old prog wolf Andy
May 11th, 2016 at 09:32
Great code! Thanks 🙂
February 16th, 2017 at 10:35
This code looks like it will fail with escaped quotes. The following is valid JSON syntax and will not be properly formatted with this code from the looks of it:
{ “hello” : “\”world\”” }
April 3rd, 2017 at 14:48
@Coder
Corrected. Thanks!
April 2nd, 2018 at 11:11
Great Code ! Worked for me with minor tweaks thanks….