自定义JSON派生格式
本文关键字:格式 派生 JSON 自定义 | 更新日期: 2023-09-27 17:53:11
我希望有一个几乎与JSON相同的序列化格式,除了键值表示为<key>="<value>"
而不是"<key>":"<value>"
。
我用Newtonsoft做了一个叫做TsonConverter
的自定义JsonConverter
,它工作得相当好,除了它不能"看到"嵌入式字典。给定以下类型:
public class TraceyData
{
[Safe]
public string Application { get; set; }
[Safe]
public string SessionID { get; set; }
[Safe]
public string TraceID { get; set; }
[Safe]
public string Workflow { get; set; }
[Safe]
public Dictionary<string, string> Tags {get; set; }
[Safe]
public string[] Stuff {get; set;}
}
和下面的代码:
TsonConverter weird = new TsonConverter();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
settings.Converters.Add(weird);
var tracey = new TraceyData();
tracey.TraceID = Guid.NewGuid().ToString();
tracey.SessionID = "5";
tracey.Tags["Referrer"] = "http://www.sky.net/deals";
tracey.Stuff = new string[] { "Alpha", "Bravo", "Charlie" };
tracey.Application = "Responsive";
string stuff = JsonConvert.SerializeObject(tracey, settings);
我得到这个:
[Application="Responsive" SessionID="5" TraceID="082ef853-92f8-4ce8-9f32-8e4f792fb022" Tags={"Referrer":"http://www.sky.net/deals"} Stuff=["Alpha","Bravo","Charlie"]]
显然我也覆盖了StartObject/EndObject表示法,用[]代替{}。除此之外,结果还不错。
但是,仍然存在内部字典的问题。为了为了转换字典以及使用我的<key>="<value>"
格式,看起来我必须做一个深度字典转换器。
我想知道是否有更简单的方法来做到这一点。
也许Newtonsoft工具有一个"属性生成器"answers"键值"生成器属性,我可以设置全局处理这个为我?
有什么建议吗?
当我们在这里的时候,我想知道是否有一个StartObject/EndObject格式化器属性重写我可以设置,这将处理我上面显示的其他自定义。这将是很好的"跳过"制作JsonConverter工具为这些类型的简单更改。
顺便说一下:
- 我的自定义JsonConverter根据我的示例中显示的
[Safe]
属性选择要序列化的属性。这是另一个很好的例子。如果JSon设置可以公开一个"属性处理程序"属性,让我覆盖通常的JSon属性,以支持我自己的,那将是美妙的。 - 我不需要反序列化这个格式。它的目的是作为一个单向操作。如果有人也想解释如何反序列化我的自定义格式,这是一个有趣的奖励,但绝对没有必要回答这个问题。
下面是我创建的TraceConverter。它引用了一个FieldMetaData
类,该类只保存属性信息。
public class TsonConverter : JsonConverter
{
public override bool CanRead
{
get
{
return false;
}
}
public override bool CanConvert(Type ObjectType)
{
return DataClassifier.TestForUserType(ObjectType);
}
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
Type objType = value.GetType();
var props = objType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var propMap = from p in props
from a in p.GetCustomAttributes(typeof(ProfileAttribute), false)
select new FieldMetaData(p, (ProfileAttribute)a);
//writer.WriteStartObject();
writer.WriteStartArray();
bool loopStarted = true;
foreach(var prop in propMap){
object rawValue = prop.GetValue(value);
if (rawValue != null || serializer.NullValueHandling == NullValueHandling.Include)
{
string jsonValue = JsonConvert.SerializeObject(prop.GetValue(value), this);
if (loopStarted)
{
loopStarted = false;
writer.WriteRaw(String.Format("{0}={1}", prop.Name, jsonValue));
}
else
{
writer.WriteRaw(String.Format(" {0}={1}", prop.Name, jsonValue));
}
}
//writer.WriteRaw(String.Format("{0}={1}", prop.Name, prop.GetValue(value)));
//writer.WritePropertyName(prop.Name, false);
//writer.WriteValue(prop.GetValue(value));
}
writer.WriteEndArray();
}
public override object ReadJson(
JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
标题>
您不需要创建自己的转换器,而是需要创建自己的JsonWriter
子类来写入自定义文件格式。(这就是Json如何。. NET实现它的BsonWriter
。在您的情况下,您的文件格式足够接近JSON,您可以从JsonTextWriter
:
public class TsonTextWriter : JsonTextWriter
{
TextWriter _writer;
public TsonTextWriter(TextWriter textWriter)
: base(textWriter)
{
if (textWriter == null)
throw new ArgumentNullException("textWriter");
QuoteName = false;
_writer = textWriter;
}
public override void WriteStartObject()
{
SetWriteState(JsonToken.StartObject, null);
_writer.Write('[');
}
protected override void WriteEnd(JsonToken token)
{
switch (token)
{
case JsonToken.EndObject:
_writer.Write(']');
break;
default:
base.WriteEnd(token);
break;
}
}
public override void WritePropertyName(string name)
{
WritePropertyName(name, true);
}
public override void WritePropertyName(string name, bool escape)
{
SetWriteState(JsonToken.PropertyName, name);
var escaped = name;
if (escape)
{
escaped = JsonConvert.ToString(name, '"', StringEscapeHandling);
escaped = escaped.Substring(1, escaped.Length - 2);
}
// Maybe also escape the space character if it appears in a name?
_writer.Write(escaped.Replace("=", @"'u003d"));// Replace "=" with unicode escape sequence.
_writer.Write('=');
}
/// <summary>
/// Writes the JSON value delimiter. (Remove this override if you want to retain the comma separator.)
/// </summary>
protected override void WriteValueDelimiter()
{
_writer.Write(' ');
}
/// <summary>
/// Writes an indent space.
/// </summary>
protected override void WriteIndentSpace()
{
// Do nothing.
}
}
这样做之后,现在当您使用此写入器时,所有类将被序列化为您的自定义格式,例如:
var tracey = new TraceyData();
tracey.TraceID = Guid.NewGuid().ToString();
tracey.SessionID = "5";
tracey.Tags["Referrer"] = "http://www.sky.net/deals";
tracey.Stuff = new string[] { "Alpha", "Bravo", "Charlie" };
tracey.Application = "Responsive";
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
using (var sw = new StringWriter())
{
using (var jsonWriter = new TsonTextWriter(sw))
{
JsonSerializer.CreateDefault(settings).Serialize(jsonWriter, tracey);
}
Debug.WriteLine(sw.ToString());
}
产生输出
[Application="Responsive" SessionID="5" TraceID="2437fe67-9788-47ba-91ce-2e5b670c2a34" Tags=[Referrer="http://www.sky.net/deals"] Stuff=["Alpha" "Bravo" "Charlie"]]
至于是否根据[Safe]
属性的存在来序列化属性,这是第二个问题。您需要创建自己的ContractResolver
并覆盖CreateProperty
,例如如下所示:使用JSON.net,当在基类上下文中使用派生类时,如何防止派生类的属性序列化?
如果您希望保留数组而不是对象的逗号分隔符,则修改WriteValueDelimiter
如下:
/// <summary>
/// Writes the JSON value delimiter. (Remove this override if you want to retain the comma separator.)
/// </summary>
protected override void WriteValueDelimiter()
{
if (WriteState == WriteState.Array)
_writer.Write(',');
else
_writer.Write(' ');
}