【问题标题】:json.net ExtensionData Modify json key name when deserializingjson.net ExtensionData 反序列化时修改json键名
【发布时间】:2016-03-10 03:15:45
【问题描述】:

我正在使用JsonExtensionData 属性和Dictionary<string, object>,它实际上对我所有的“未知” JSON 结果都非常有效。

不幸的是,我从我的 web 服务获得的 JSON 字符串有时会给我带有非字母数字字符的键,我想在反序列化期间对其进行清理。

例如:

"dc:title":"My Document title"

在反序列化期间,我想删除所有非字母数字字符,我想知道是否有使用自定义转换器的简单方法?

反序列化代码

public class TikaDeserializer : IDeserializer
{
    private Newtonsoft.Json.JsonSerializer serializer;


    public TikaDeserializer(Newtonsoft.Json.JsonSerializer serializer)
    {
        this.serializer = serializer;
    }

    public T Deserialize<T>(RestSharp.IRestResponse response)
    {
        var content = response.Content;

        using(var stringReader = new StringReader(content))
        {
            using(var jsonTextReader = new JsonTextReader(stringReader))
            {
                return serializer.Deserialize<T>(jsonTextReader);
            }
        }
    }

    public string DateFormat { get; set; }

    public string Namespace { get; set; }

    public string RootElement { get; set; }

    public static TikaDeserializer Default
    {
        get
        {
            return new TikaDeserializer(new Newtonsoft.Json.JsonSerializer()
            {
                NullValueHandling = NullValueHandling.Ignore,
            });
        }
    }

Gediminas 的转换器代码

public class InputKeyNameCleanerConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JToken.ReadFrom(reader);
        foreach(JToken token in jObject.ToList())
        {
            string replacedName = Regex.Replace(token.Path, @"[^A-Za-z]", String.Empty);
            JProperty newToken = new JProperty(replacedName, token.First);
            token.Replace(newToken);
        }
        return jObject.ToObject(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }
}

型号

public class ParsedDocument
{

    [JsonProperty("Author")]
    public string Author { get; set; }
    [JsonProperty("Content-Type")]
    public string ContentType { get; set; }
    [JsonProperty("Content-Encoding")]
    public string ContentEncoding { get; set; }
    [JsonProperty("Creation-Date")]
    public DateTime? DateCreated { get; set; }
    [JsonProperty("Last-Modified")]
    public DateTime? DateModified { get; set; }
    [JsonProperty("Last-Save-Date")]
    public DateTime? DateSaved { get; set; }
    [JsonProperty("Last-Printed")]
    public DateTime? DatePrinted { get; set; }

    [JsonProperty("title")]
    public string Title { get; set; }
    [JsonProperty("X-TIKA:content")]
    public string Content { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> MetaData { get; set; }




}

【问题讨论】:

  • 尝试像这样使用动态(动态数据 = deserialiseJson(JsonString);

标签: c# json.net deserialization


【解决方案1】:

您可以使用替换JsonObjectContract.ExtensionDataSetter 委托的custom contract resolver 来执行此操作:

public class ExtensionNameMappingContractResolver : IContractResolver
{
    readonly IContractResolver baseResolver;
    readonly Regex regex;
    readonly string replacement;

    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."

    static ExtensionNameMappingContractResolver removeNonAlphanumericCharactersInstance;

    static ExtensionNameMappingContractResolver()
    {
        // Regex is from https://stackoverflow.com/questions/8779189/how-do-i-strip-non-alphanumeric-characters-including-spaces-from-a-string
        removeNonAlphanumericCharactersInstance = new ExtensionNameMappingContractResolver(new DefaultContractResolver(), new Regex(@"[^\p{L}\p{N}]+"), "");
    }

    public static ExtensionNameMappingContractResolver RemoveNonAlphanumericCharactersInstance { get { return removeNonAlphanumericCharactersInstance; } }

    public ExtensionNameMappingContractResolver(IContractResolver baseResolver, Regex regex, string replacement)
    {
        if (regex == null || replacement == null || baseResolver == null)
            throw new ArgumentNullException();
        this.regex = regex;
        this.replacement = replacement;
        this.baseResolver = baseResolver;
    }

    #region IContractResolver Members

    public JsonContract ResolveContract(Type type)
    {
        var contract = baseResolver.ResolveContract(type);
        if (contract is JsonObjectContract)
        {
            var objContract = (JsonObjectContract)contract;
            if (objContract.ExtensionDataSetter != null)
            {
                var oldSetter = objContract.ExtensionDataSetter;
                objContract.ExtensionDataSetter = (o, key, value) =>
                {
                    var newKey = regex.Replace(key, replacement);
                    oldSetter(o, newKey, value);
                };
            }
        }
        return contract;
    }

    #endregion
}

然后像这样使用它:

        var settings = new JsonSerializerSettings 
        {
             NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = ExtensionNameMappingContractResolver.RemoveNonAlphanumericCharactersInstance 
        };
        var serializer = JsonSerializer.CreateDefault(settings);

请注意,我使用的Regex 替换了table of Unicode character categories 定义的所有Unicode 非字母数字字符。有关更多选项,包括删除所有非 ASCII、非字母数字字符,请参阅How do I strip non-alphanumeric characters (including spaces) from a string?

请注意,如果通过从属性名称中删除非字母数字字符,您的合约解析器尝试添加重复的扩展数据键,则会抛出 JsonSerializationException: Error setting value in extension data ---&gt; System.ArgumentException: An item with the same key has already been added

【讨论】:

  • 你太棒了!非常感谢!
【解决方案2】:

当然!您可以使用正则表达式。您可以使用[^a-zA-Z0-9] 匹配任何非字母数字字符,并将其替换为空字符串。在您的 JsonConverter 中,您可以创建一个 JObject 并迭代它的属性,将它们替换为具有更正名称的属性。

我想出了一个通用解决方案,它接受 Regex 对象和 replacement 字符串作为构造函数参数:

实施:

class DictionaryRegexReplaceJsonConverter : JsonConverter
{
    public Regex ReplacingRegex { get; set; }
    public string Replacement { get; set; }

    public DictionaryRegexReplaceJsonConverter(Regex replacingRegex, string replacement = "")
    {
        ReplacingRegex = replacingRegex;
        Replacement = replacement;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jo = JToken.ReadFrom(reader);
        foreach (JToken token in jo.ToList())
        {
            string replacedName = ReplacingRegex.Replace(token.Path, Replacement);
            JProperty newToken = new JProperty(replacedName, token.First);
            token.Replace(newToken);
        }
        return jo.ToObject(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }
}

用法:

Regex regex = new Regex("[^a-zA-Z0-9]");
var converter = new DictionaryKeyReplacingJsonConverter(regex);
string json = "{\"dc:title\":\"My Document title\", \"Another Example!\": \"foo\"}";

// {"dctitle": "My Document title", "AnotherExample": "foo"} ]
var obj = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, converter);

如果关注性能,可以通过手动读取JsonReader 并形成您的对象,而不是使用 JObject 和替换属性来更优化。

【讨论】:

  • 谢谢。如果我遵循您的代码,那效果很好。有没有办法将它与 ExtensionData Attribute 结合起来? [JsonExtensionData] public Dictionary 元数据 { get;放;我试图添加一个 [JsonConverter(typeof(MyConverter)] 但无法识别:-(
猜你喜欢
  • 1970-01-01
  • 2014-03-14
  • 1970-01-01
  • 1970-01-01
  • 2015-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多