C#格式的JSON,其值带有反斜杠"\" [英] C# format JSON with backslash '\' in value

查看:4380
本文介绍了C#格式的JSON,其值带有反斜杠"\"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些来自第三方系统的JSON,其值中包含反斜杠.例如:

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

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

其中没有转义c#字符串的

对应于字符串:

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

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

我希望能够格式化(例如缩进)此JSON.

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

通常用于格式化,我可能会使用类似JsonConvert这样的东西:

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

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

这不是很有效,因为它将值视为日期,但是由于它不是标准的MS格式\/Date(ticks)\/,所以它的日期是1970年1月1日:

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)/"
}

有没有一种方法可以用C#格式(带有或不带有JsonConvert)格式化JSON,从而将反斜杠保留在值中?

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

请注意,我要处理的真实JSON(a)相当大,但对于某些正则表达式/查找替换解决方案来说并不太大,如果确实有必要(b)不在我的控制之下,那么我无法更改格式.我确定答案已经在StackOverflow上,但是我发现很难找到正确的搜索词...

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

推荐答案

基本问题是,在JSON字符串文字中,的含义与未转义的固相线"/" 完全相同,并且Json.NET在很低的层次上解析和解释了这种转义,即 JsonTextReader.ReadStringIntoBuffer() .因此,高级代码无法检测并记住字符串文字是设置为"\/Date(2015-02-02)\/"还是"/Date(2015-02-02)/"格式,并在以后适当时回写一个或另一个.

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.

如果您对总是没问题,可以在以/Date(开头并以)/结尾的字符串中添加额外的转义符,则可以使用

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);
        }
    }
}

然后使用 DateParseHandling = DateParseHandling.None 进行解析:

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);

此打印:

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

这篇关于C#格式的JSON,其值带有反斜杠"\"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆