问题
I have a question or rather an issue with the JObject. This is just a small example, I have large lists with more than 20 elements and I am saving these in JSON format and it is really bad to read if every value is in a new line. Can someone explain to me how to fix this?
Code:
var myObj = new
{
Vector = new List<int>{
1,2,3,4,5
}
};
Console.WriteLine(JToken.FromObject(myObj).ToString(Formatting.Indented));
Output is like this:
{
"Vector": [
1,
2,
3,
4,
5
]
}
But I want it to be like this:
{
"Vector": [1,2,3,4,5]
}
I already tried to override the ToString()
from MyObj
but it doesn't work either.
回答1:
There is no method to control the formatting of specific nested tokens inside a JToken
hierarchy when writing to JSON. Thus we will need to roll our own:
public static partial class JsonExtensions
{
public static string ToFormattedString(this JToken token, params JsonConverter[] converters)
{
if (token == null)
throw new ArgumentNullException();
using (var sw = new StringWriter(CultureInfo.InvariantCulture))
{
using (var jw = new JsonTextWriter(sw) { Formatting = Formatting.Indented })
FormattedWriteTo(token, jw, 0, converters);
return sw.ToString();
}
}
static void FormattedWriteTo(JToken token, JsonTextWriter writer, int depth, params JsonConverter[] converters)
{
if (token == null)
{
writer.WriteNull();
}
else if (token is JObject obj)
{
IList<JToken> asList = obj;
writer.WriteStartObject();
for (int i = 0, n = asList.Count; i < n; i++)
FormattedWriteTo(asList[i], writer, depth+1, converters);
writer.WriteEndObject();
}
else if (token is JArray array)
{
// Disable formatting for arrays.
// You could smarten this up further by e.g. checking to see whether the array contents are all primitive JValue tokens.
var old = writer.Formatting;
// The question requires an extra space between the property name and the array value.
if (depth > 0 && old == Formatting.Indented)
writer.WriteWhitespace(" ");
writer.Formatting = Formatting.None;
writer.WriteStartArray();
for (int i = 0, n = array.Count; i < n; i++)
FormattedWriteTo(array[i], writer, depth+1, converters);
writer.WriteEndArray();
writer.Formatting = old;
}
else if (token is JProperty property)
{
writer.WritePropertyName(property.Name);
FormattedWriteTo(property.Value, writer, depth+1, converters);
}
else
{
// JValue, JRaw, JConstructor
token.WriteTo(writer);
}
}
}
Then JToken.FromObject(myObj).ToFormattedString()
produces, as required:
{
"Vector": [1,2,3,4,5]
}
Notes:
- If you were serializing
myObj
directly you would be able to use a custom JsonConverter for theList<int>
to disable formatting, as shown in How to apply indenting serialization only to some properties? and Newtonsoft inline formatting for subelement while serializing. But because you are writing an already-serializedJToken
hierarchy, the serializer is not invoked and a custom converter for arrays will not be called.
Demo fiddle here.
来源:https://stackoverflow.com/questions/65304693/jobject-tostring-formatting-issue-for-jarray