自定义JSON派生格式



我希望有一个几乎与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工具有一个"属性生成器"one_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(' ');
    }

相关内容

  • 没有找到相关文章

最新更新