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….