C# format JSON with backslash '\' in value

佐手、 提交于 2019-12-10 18:09:07

问题


I have some JSON from a third party system that contains backslashes in the value. For example:

string extract = @"{""key"": ""\/Date(2015-02-02)\/""}";

which without the c# string escaping corresponds to the string:

{"key": "\/Date(2015-02-02)\/"}

I'd like to be able to format (e.g. indent) this JSON.

Typically for formatting, I might use something like JsonConvert like so:

JsonConvert.SerializeObject(JsonConvert.DeserializeObject(extract), Formatting.Indented)

This doesn't quite work, as it sees the value as a date, but as it's not in the standard MS format of \/Date(ticks)\/, it goes to a date of 1 Jan 1970:

{
  "key": "1970-01-01T00:00:02.015+00:00"
}

Next approach is to use the serializer settings to not convert dates (I'm not bothered whether it recognises the field as a date, although it would probably be handy later on):

JsonSerializerSettings settings = new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None,
};

JsonConvert.SerializeObject(JsonConvert.DeserializeObject(extract, settings), Formatting.Indented);

This appears to have treated the backslash as an escape character during the deserialization, so it is "lost" once I see the final result:

{
  "key": "/Date(2015-02-02)/"
}

Is there a way that I can format the JSON in C# (with or without JsonConvert), that will preserve the backslash in the value?

Note that the real JSON I am dealing with is (a) reasonably large, but not too large for some regex/find-replace solution, if really necessary (b) not under my control, so I can't change the format. I'm sure the answer is already on StackOverflow, but I'm finding it difficult to find the right search terms...


回答1:


The basic problem is that, in a JSON string literal, the escaped solidus "\/" means exactly the same as the unescaped solidus "/", and Json.NET parses and interprets this escaping at a very low level, namely JsonTextReader.ReadStringIntoBuffer(). Thus there's no way for higher level code to detect and remember whether a string literal was formatted as "\/Date(2015-02-02)\/" or "/Date(2015-02-02)/" and later write back one or the other as appropriate.

If you are OK with always adding the extra escaping to strings that start with /Date( and end with )/, you can use a custom subclass of JsonTextWriter to do this:

public class DateLiteralJsonTextWriter : JsonTextWriter
{
    public DateLiteralJsonTextWriter(TextWriter writer) : base(writer) { }

    public override void WriteValue(string value)
    {
        const string startToken = @"/Date(";
        const string replacementStartToken = @"\/Date(";
        const string endToken = @")/";
        const string replacementEndToken = @")\/";

        if (value != null && value.StartsWith(startToken) && value.EndsWith(endToken))
        {
            var sb = new StringBuilder();

            // Add the initial quote.
            sb.Append(QuoteChar);

            // Add the new start token.
            sb.Append(replacementStartToken);

            // Add any necessary escaping to the innards of the "/Date(.*)/" string.
            using (var writer = new StringWriter(sb))
            using (var jsonWriter = new JsonTextWriter(writer) { StringEscapeHandling = this.StringEscapeHandling, Culture = this.Culture, QuoteChar = '\"' })
            {
                var content = value.Substring(startToken.Length, value.Length - startToken.Length - endToken.Length);
                jsonWriter.WriteValue(content);
            }

            // Strip the embedded quotes from the above.
            sb.Remove(replacementStartToken.Length + 1, 1);
            sb.Remove(sb.Length - 1, 1);

            // Add the replacement end token and final quote.
            sb.Append(replacementEndToken);
            sb.Append(QuoteChar);

            // Write without any further escaping.
            WriteRawValue(sb.ToString());
        }
        else
        {
            base.WriteValue(value);
        }
    }
}

Then parse with DateParseHandling = DateParseHandling.None as you are currently doing:

var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };

var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var jsonWriter = new DateLiteralJsonTextWriter(writer) { Formatting = Formatting.Indented})
{
    JsonSerializer.CreateDefault(settings).Serialize(jsonWriter,  JsonConvert.DeserializeObject(extract, settings));
}

Console.WriteLine(sb);

This prints:

{
  "key": "\/Date(2015-02-02)\/"
}



回答2:


Have you tried:

extract = extract.Replace("\\","\\\\");

before parsing the string?




回答3:


I hope this can help, Serializing Dates in JSON:

http://www.newtonsoft.com/json/help/html/datesinjson.htm



来源:https://stackoverflow.com/questions/36474609/c-sharp-format-json-with-backslash-in-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!