serialize serializar pretty not newtonsoft net libreria example deserializar c# json formatting

serializar - Formateador JSON en C#?



serializar y deserializar json c# (15)

Buscando una función que tomará una string de Json como entrada y la formateará con saltos de línea y sangrías. La validación sería una ventaja, pero no es necesaria, y no es necesario analizarla en un objeto ni nada.

Alguien sabe de una biblioteca así?

Muestra de entrada:

{"status":"OK", "results":[ {"types":[ "locality", "political"], "formatted_address":"New York, NY, USA", "address_components":[ {"long_name":"New York", "short_name":"New York", "types":[ "locality", "political"]}, {"long_name":"New York", "short_name":"New York", "types":[ "administrative_area_level_2", "political"]}, {"long_name":"New York", "short_name":"NY", "types":[ "administrative_area_level_1", "political"]}, {"long_name":"United States", "short_name":"US", "types":[ "country", "political"]}], "geometry":{"location":{"lat":40.7143528, "lng":-74.0059731}, "location_type":"APPROXIMATE", "viewport":{"southwest":{"lat":40.5788964, "lng":-74.2620919}, "northeast":{"lat":40.8495342, "lng":-73.7498543}}, "bounds":{"southwest":{"lat":40.4773990, "lng":-74.2590900}, "northeast":{"lat":40.9175770, "lng":-73.7002720}}}}]}


Actualicé la versión anterior, ahora debe admitir valores sin comillas como enteros y booleanos.

Refactoré la versión anterior y obtuve la versión final: el código es más corto y más limpio. Solo requiere un método de extensión. Lo más importante: corrigió algunos errores.

class JsonHelper { private const string INDENT_STRING = " "; public static string FormatJson(string str) { var indent = 0; var quoted = false; var sb = new StringBuilder(); for (var i = 0; i < str.Length; i++) { var ch = str[i]; switch (ch) { case ''{'': case ''['': sb.Append(ch); if (!quoted) { sb.AppendLine(); Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING)); } break; case ''}'': case '']'': if (!quoted) { sb.AppendLine(); Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING)); } sb.Append(ch); break; case ''"'': sb.Append(ch); bool escaped = false; var index = i; while (index > 0 && str[--index] == ''//') escaped = !escaped; if (!escaped) quoted = !quoted; break; case '','': sb.Append(ch); if (!quoted) { sb.AppendLine(); Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING)); } break; case '':'': sb.Append(ch); if (!quoted) sb.Append(" "); break; default: sb.Append(ch); break; } } return sb.ToString(); } } static class Extensions { public static void ForEach<T>(this IEnumerable<T> ie, Action<T> action) { foreach (var i in ie) { action(i); } } }


Aquí hay una versión compacta de un embellecedor JSON.

private const string INDENT_STRING = " "; static string FormatJson(string json) { int indentation = 0; int quoteCount = 0; var result = from ch in json let quotes = ch == ''"'' ? quoteCount++ : quoteCount let lineBreak = ch == '','' && quotes % 2 == 0 ? ch + Environment.NewLine + String.Concat(Enumerable.Repeat(INDENT_STRING, indentation)) : null let openChar = ch == ''{'' || ch == ''['' ? ch + Environment.NewLine + String.Concat(Enumerable.Repeat(INDENT_STRING, ++indentation)) : ch.ToString() let closeChar = ch == ''}'' || ch == '']'' ? Environment.NewLine + String.Concat(Enumerable.Repeat(INDENT_STRING, --indentation)) + ch : ch.ToString() select lineBreak == null ? openChar.Length > 1 ? openChar : closeChar : lineBreak; return String.Concat(result); }

Productos:

{ "status":"OK", "results":[ { "types":[ "locality", "political" ], "formatted_address":"New York, NY, USA", "address_components":[ { "long_name":"New York", "short_name":"New York", "types":[ "locality", "political" ] }, { "long_name":"New York", "short_name":"New York", "types":[ "administrative_area_level_2", "political" ] }, { "long_name":"New York", "short_name":"NY", "types":[ "administrative_area_level_1", "political" ] }, { "long_name":"United States", "short_name":"US", "types":[ "country", "political" ] } ], "geometry":{ "location":{ "lat":40.7143528, "lng":-74.0059731 }, "location_type":"APPROXIMATE", "viewport":{ "southwest":{ "lat":40.5788964, "lng":-74.2620919 }, "northeast":{ "lat":40.8495342, "lng":-73.7498543 } }, "bounds":{ "southwest":{ "lat":40.4773990, "lng":-74.2590900 }, "northeast":{ "lat":40.9175770, "lng":-73.7002720 } } } } ] }


Como señaló benjymous , puedes usar Newtonsoft.Json con un objeto temporal y deserializar / serializar.

var obj = JsonConvert.DeserializeObject(jsonString); var formatted = JsonConvert.SerializeObject(obj, Formatting.Indented);


Ejemplo

public static string JsonFormatter(string json) { StringBuilder builder = new StringBuilder(); bool quotes = false; bool ignore = false; int offset = 0; int position = 0; if (string.IsNullOrEmpty(json)) { return string.Empty; } json = json.Replace(Environment.NewLine, "").Replace("/t", ""); foreach (char character in json) { switch (character) { case ''"'': if (!ignore) { quotes = !quotes; } break; case ''/''': if (quotes) { ignore = !ignore; } break; } if (quotes) { builder.Append(character); } else { switch (character) { case ''{'': case ''['': builder.Append(character); builder.Append(Environment.NewLine); builder.Append(new string('' '', ++offset * 4)); break; case ''}'': case '']'': builder.Append(Environment.NewLine); builder.Append(new string('' '', --offset * 4)); builder.Append(character); break; case '','': builder.Append(character); builder.Append(Environment.NewLine); builder.Append(new string('' '', offset * 4)); break; case '':'': builder.Append(character); builder.Append('' ''); break; default: if (character != '' '') { builder.Append(character); } break; } position++; } } return builder.ToString().Trim(); }


Esta es una variante de la respuesta aceptada que me gusta usar. Las partes comentadas resultan en lo que considero un formato más legible (necesitaría comentar el código adyacente para ver la diferencia):

public class JsonHelper { private const int INDENT_SIZE = 4; public static string FormatJson(string str) { str = (str ?? "").Replace("{}", @"/{/}").Replace("[]", @"/[/]"); var inserts = new List<int[]>(); bool quoted = false, escape = false; int depth = 0/*-1*/; for (int i = 0, N = str.Length; i < N; i++) { var chr = str[i]; if (!escape && !quoted) switch (chr) { case ''{'': case ''['': inserts.Add(new[] { i, +1, 0, INDENT_SIZE * ++depth }); //int n = (i == 0 || "{[,".Contains(str[i - 1])) ? 0 : -1; //inserts.Add(new[] { i, n, INDENT_SIZE * ++depth * -n, INDENT_SIZE - 1 }); break; case '','': inserts.Add(new[] { i, +1, 0, INDENT_SIZE * depth }); //inserts.Add(new[] { i, -1, INDENT_SIZE * depth, INDENT_SIZE - 1 }); break; case ''}'': case '']'': inserts.Add(new[] { i, -1, INDENT_SIZE * --depth, 0 }); //inserts.Add(new[] { i, -1, INDENT_SIZE * depth--, 0 }); break; case '':'': inserts.Add(new[] { i, 0, 1, 1 }); break; } quoted = (chr == ''"'') ? !quoted : quoted; escape = (chr == ''//') ? !escape : false; } if (inserts.Count > 0) { var sb = new System.Text.StringBuilder(str.Length * 2); int lastIndex = 0; foreach (var insert in inserts) { int index = insert[0], before = insert[2], after = insert[3]; bool nlBefore = (insert[1] == -1), nlAfter = (insert[1] == +1); sb.Append(str.Substring(lastIndex, index - lastIndex)); if (nlBefore) sb.AppendLine(); if (before > 0) sb.Append(new String('' '', before)); sb.Append(str[index]); if (nlAfter) sb.AppendLine(); if (after > 0) sb.Append(new String('' '', after)); lastIndex = index + 1; } str = sb.ToString(); } return str.Replace(@"/{/}", "{}").Replace(@"/[/]", "[]"); } }


Esto pondrá cada artículo en una nueva línea

VB.NET

mytext = responseFromServer.Replace("{", vbNewLine + "{")

DO#

mytext = responseFromServer.Replace("{", Environment.Newline + "{")


Incluso el más simple que acabo de escribir:

public class JsonFormatter { public static string Indent = " "; public static string PrettyPrint(string input) { var output = new StringBuilder(input.Length * 2); char? quote = null; int depth = 0; for(int i=0; i<input.Length; ++i) { char ch = input[i]; switch (ch) { case ''{'': case ''['': output.Append(ch); if (!quote.HasValue) { output.AppendLine(); output.Append(Indent.Repeat(++depth)); } break; case ''}'': case '']'': if (quote.HasValue) output.Append(ch); else { output.AppendLine(); output.Append(Indent.Repeat(--depth)); output.Append(ch); } break; case ''"'': case ''/''': output.Append(ch); if (quote.HasValue) { if (!output.IsEscaped(i)) quote = null; } else quote = ch; break; case '','': output.Append(ch); if (!quote.HasValue) { output.AppendLine(); output.Append(Indent.Repeat(depth)); } break; case '':'': if (quote.HasValue) output.Append(ch); else output.Append(" : "); break; default: if (quote.HasValue || !char.IsWhiteSpace(ch)) output.Append(ch); break; } } return output.ToString(); } }

Extensiones necesarias:

public static string Repeat(this string str, int count) { return new StringBuilder().Insert(0, str, count).ToString(); } public static bool IsEscaped(this string str, int index) { bool escaped = false; while (index > 0 && str[--index] == ''//') escaped = !escaped; return escaped; } public static bool IsEscaped(this StringBuilder str, int index) { return str.ToString().IsEscaped(index); }

Muestra de salida:

{ "status" : "OK", "results" : [ { "types" : [ "locality", "political" ], "formatted_address" : "New York, NY, USA", "address_components" : [ { "long_name" : "New York", "short_name" : "New York", "types" : [ "locality", "political" ] }, { "long_name" : "New York", "short_name" : "New York", "types" : [ "administrative_area_level_2", "political" ] }, { "long_name" : "New York", "short_name" : "NY", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "United States", "short_name" : "US", "types" : [ "country", "political" ] } ], "geometry" : { "location" : { "lat" : 40.7143528, "lng" : -74.0059731 }, "location_type" : "APPROXIMATE", "viewport" : { "southwest" : { "lat" : 40.5788964, "lng" : -74.2620919 }, "northeast" : { "lat" : 40.8495342, "lng" : -73.7498543 } }, "bounds" : { "southwest" : { "lat" : 40.4773990, "lng" : -74.2590900 }, "northeast" : { "lat" : 40.9175770, "lng" : -73.7002720 } } } } ] }


J Bryan Price, un buen ejemplo, pero hay deficiencias

{/"response/":[123, 456, {/"name/":/"John/"}, {/"count/":3}]}

después de formatear

{ "response" : [ 123, 456, { "name" : "John" }, { "count" : 3 } ] }

sesgo inapropiado :(


La razón principal de escribir su propia función es que los marcos JSON generalmente realizan análisis de cadenas en tipos .NET y convirtiéndolos de nuevo en cadenas, lo que puede ocasionar la pérdida de cadenas originales. Por ejemplo, 0.0002 se convierte en 2E-4

No publico mi función (es bastante similar a la otra aquí), pero aquí están los casos de prueba

using System.IO; using Newtonsoft.Json; using NUnit.Framework; namespace json_formatter.tests { [TestFixture] internal class FormatterTests { [Test] public void CompareWithNewtonsofJson() { string file = Path.Combine(TestContext.CurrentContext.TestDirectory, "json", "minified.txt"); string json = File.ReadAllText(file); string newton = JsonPrettify(json); // Double space are indent symbols which newtonsoft framework uses string my = new Formatter(" ").Format(json); Assert.AreEqual(newton, my); } [Test] public void EmptyArrayMustNotBeFormatted() { var input = "{/"na{me/": []}"; var expected = "{/r/n/t/"na{me/": []/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void EmptyObjectMustNotBeFormatted() { var input = "{/"na{me/": {}}"; var expected = "{/r/n/t/"na{me/": {}/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void MustAddLinebreakAfterBraces() { var input = "{/"name/": /"value/"}"; var expected = "{/r/n/t/"name/": /"value/"/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void MustFormatNestedObject() { var input = "{/"na{me/":/"val}ue/", /"name1/": {/"name2/":/"value/"}}"; var expected = "{/r/n/t/"na{me/": /"val}ue/",/r/n/t/"name1/": {/r/n/t/t/"name2/": /"value/"/r/n/t}/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void MustHandleArray() { var input = "{/"name/": /"value/", /"name2/":[/"a/", /"b/", /"c/"]}"; var expected = "{/r/n/t/"name/": /"value/",/r/n/t/"name2/": [/r/n/t/t/"a/",/r/n/t/t/"b/",/r/n/t/t/"c/"/r/n/t]/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void MustHandleArrayOfObject() { var input = "{/"name/": /"value/", /"name2/":[{/"na{me/":/"val}ue/"}, {/"nam///"e2/":/"val///////"ue/"}]}"; var expected = "{/r/n/t/"name/": /"value/",/r/n/t/"name2/": [/r/n/t/t{/r/n/t/t/t/"na{me/": /"val}ue/"/r/n/t/t},/r/n/t/t{/r/n/t/t/t/"nam///"e2/": /"val///////"ue/"/r/n/t/t}/r/n/t]/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void MustHandleEscapedString() { var input = "{/"na{me/":/"val}ue/", /"name1/": {/"nam///"e2/":/"val///////"ue/"}}"; var expected = "{/r/n/t/"na{me/": /"val}ue/",/r/n/t/"name1/": {/r/n/t/t/"nam///"e2/": /"val///////"ue/"/r/n/t}/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void MustIgnoreEscapedQuotesInsideString() { var input = "{/"na{me///"/": /"val}ue/"}"; var expected = "{/r/n/t/"na{me///"/": /"val}ue/"/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [TestCase(" ")] [TestCase("/"")] [TestCase("{")] [TestCase("}")] [TestCase("[")] [TestCase("]")] [TestCase(":")] [TestCase(",")] public void MustIgnoreSpecialSymbolsInsideString(string symbol) { string input = "{/"na" + symbol + "me/": /"val" + symbol + "ue/"}"; string expected = "{/r/n/t/"na" + symbol + "me/": /"val" + symbol + "ue/"/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } [Test] public void StringEndsWithEscapedBackslash() { var input = "{/"na{me/////": /"val}ue/"}"; var expected = "{/r/n/t/"na{me/////": /"val}ue/"/r/n}"; Assert.AreEqual(expected, new Formatter().Format(input)); } private static string PrettifyUsingNewtosoft(string json) { using (var stringReader = new StringReader(json)) using (var stringWriter = new StringWriter()) { var jsonReader = new JsonTextReader(stringReader); var jsonWriter = new JsonTextWriter(stringWriter) { Formatting = Formatting.Indented }; jsonWriter.WriteToken(jsonReader); return stringWriter.ToString(); } } } }


Lo solucionó ... de alguna manera.

public class JsonFormatter { #region class members const string Space = " "; const int DefaultIndent = 0; const string Indent = Space + Space + Space + Space; static readonly string NewLine = Environment.NewLine; #endregion private enum JsonContextType { Object, Array } static void BuildIndents(int indents, StringBuilder output) { indents += DefaultIndent; for (; indents > 0; indents--) output.Append(Indent); } bool inDoubleString = false; bool inSingleString = false; bool inVariableAssignment = false; char prevChar = ''/0''; Stack<JsonContextType> context = new Stack<JsonContextType>(); bool InString() { return inDoubleString || inSingleString; } public string PrettyPrint(string input) { var output = new StringBuilder(input.Length * 2); char c; for (int i = 0; i < input.Length; i++) { c = input[i]; switch (c) { case ''{'': if (!InString()) { if (inVariableAssignment || (context.Count > 0 && context.Peek() != JsonContextType.Array)) { output.Append(NewLine); BuildIndents(context.Count, output); } output.Append(c); context.Push(JsonContextType.Object); output.Append(NewLine); BuildIndents(context.Count, output); } else output.Append(c); break; case ''}'': if (!InString()) { output.Append(NewLine); context.Pop(); BuildIndents(context.Count, output); output.Append(c); } else output.Append(c); break; case ''['': output.Append(c); if (!InString()) context.Push(JsonContextType.Array); break; case '']'': if (!InString()) { output.Append(c); context.Pop(); } else output.Append(c); break; case ''='': output.Append(c); break; case '','': output.Append(c); if (!InString() && context.Peek() != JsonContextType.Array) { BuildIndents(context.Count, output); output.Append(NewLine); BuildIndents(context.Count, output); inVariableAssignment = false; } break; case ''/''': if (!inDoubleString && prevChar != ''//') inSingleString = !inSingleString; output.Append(c); break; case '':'': if (!InString()) { inVariableAssignment = true; output.Append(Space); output.Append(c); output.Append(Space); } else output.Append(c); break; case ''"'': if (!inSingleString && prevChar != ''//') inDoubleString = !inDoubleString; output.Append(c); break; case '' '': if (InString()) output.Append(c); break; default: output.Append(c); break; } prevChar = c; } return output.ToString(); } }

credit [enlace muerto]


Muestra más corta para la biblioteca json.net.

using Newtonsoft.Json; private static string format_json(string json) { dynamic parsedJson = JsonConvert.DeserializeObject(json); return JsonConvert.SerializeObject(parsedJson, Formatting.Indented); }

PD: puede envolver el texto json formateado con una etiqueta para imprimir tal como está en la página html.


Necesita omitir /r y /n en PrettyPrint() . La salida parece divertida de que ya hay algunos crlf (o la fuente ya estaba formateada).


También puede usar la biblioteca Newtonsoft.Json para esto y llamar a SerializeObject con el formato. Enum -

var x = JsonConvert.SerializeObject(jsonString, Formatting.Indented);

Documentación: serializar un objeto

Actualización -

Solo lo intenté de nuevo. Estoy bastante seguro de que esto solía funcionar; tal vez haya cambiado en una versión posterior o tal vez solo estoy imaginando cosas. De todos modos, según los comentarios a continuación, no funciona como se esperaba. Estos sí, sin embargo (recién probado en linqpad). El primero es de los comentarios, el segundo es un ejemplo que encontré en otro lugar en SO -

void Main() { //Example 1 var t = "{/"x/":57,/"y/":57.0,/"z/":/"Yes/"}"; var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(t); var f = Newtonsoft.Json.JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented); Console.WriteLine(f); //Example 2 JToken jt = JToken.Parse(t); string formatted = jt.ToString(Newtonsoft.Json.Formatting.Indented); Console.WriteLine(formatted); //Example 2 in one line - Console.WriteLine(JToken.Parse(t).ToString(Newtonsoft.Json.Formatting.Indented)); }


Todos los créditos son para Frank Tzanabetis. Sin embargo, este es el ejemplo directo más corto, que también sobrevive en caso de cadena vacía o cadena JSON original rota:

using Newtonsoft.Json; using Newtonsoft.Json.Linq; ... private static string Format(string jsonString) { try { return JToken.Parse(jsonString).ToString(Formatting.Indented); } catch { return jsonString; } }


Ya hay un montón de excelentes respuestas aquí que usan Newtonsoft.JSON , pero aquí hay una más que usa JObject.Parse en combinación con ToString() , ya que aún no se ha mencionado:

var jObj = Newtonsoft.Json.Linq.JObject.Parse(json); var formatted = jObj.ToString(Newtonsoft.Json.Formatting.Indented);