C#格式的JSON,其值带有反斜杠"\" [英] C# format JSON with backslash '\' in value
问题描述
我有一些来自第三方系统的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屋!