从自定义 Json 转换器中操作 Json 字符串 [英] Manipulating a Json string from within a custom Json Converter

查看:56
本文介绍了从自定义 Json 转换器中操作 Json 字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了提出我的问题,我将参考@Brian Rogers 的回答此处.在这个答案中 ReadJson 正在做一些相对简单的事情.但是,如何在其中添加一个层,以便在将传入的 Json 字符串反序列化为对象然后返回之前对其进行操作?

In order to ask my question, I will be referring to @Brian Rogers 's answer here. In this answer ReadJson is doing something relatively simple. How could I however add a layer in there in order to manipulate the incoming Json string before deserialising it into an object and then returning it?

这是我想做的事情类型(Brian 的 WrappedObjectConvert 类的修改版本):

Here is the type of things I would like to do (modified version of Brian's WrappedObjectConvert class):

class WrappedObjectConverter : JsonConverter
{
    private string CustomParsing(string jsonString)
    {
         string modifiedJsonString;

         // Some renaming
         modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")CarName(?="":\s)", "Myname", RegexOptions.IgnoreCase);

         modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")CustName(?="":\s)", "Myname", RegexOptions.IgnoreCase);

         modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")MyName(?="":\s)", "Myname", RegexOptions.IgnoreCase);

         modifiedJsonString= Regex.Replace(modifiedJsonString, $@"(?<="")SomeAddr(?="":\s)", "AddressLine1 ", RegexOptions.IgnoreCase);

         // Renaming IsPublic true/false to IsPrivate false/true
        modifiedJsonString= Regex.Replace(modifiedJsonString, "\"IsPublic\": true,", "\"IsPrivate\": false,", RegexOptions.IgnoreCase);
        modifiedJsonString = Regex.Replace(modifiedJsonString, "\"IsPublic\": false,", "\"IsPrivate\": true,", RegexOptions.IgnoreCase);
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);

        string modifiedJsonString = CustomParsing(token.ToString());

        return ????;  // How to return the object

        // I could do something of the sort, but not sure it's got its place here:  
        // return JsonConvert.DeserializeObject<RootObject>(modifiedJsonString );  
    }

    public override bool CanWrite
    {
        get { return false; }
    }

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

客户端类也通过添加字段IsPrivate"进行了轻微修改:

The client class has also been slightly modified by adding the field "IsPrivate":

public class Client
{
    [JsonConverter(typeof(WrappedObjectConverter))]
    public List<Product> ProductList { get; set; }

    [JsonConverter(typeof(WrappedObjectConverter))]
    public string Name { get; set; }

    [JsonConverter(typeof(WrappedObjectConverter))]
    public bool IsPrivate { get; set; }

    [JsonConverter(typeof(WrappedObjectConverter))]
    public string AddressLine1 { get; set; }
}

以及修改了Json的demo(有些标签已经从Brian的例子中改变了,需要解析和修改):

And the demo with a modified Json (some labels have been changed from Brian's example, which need to be parsed and modified):

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""Result"": {
                ""Client"": {
                    ""ProductList"": {
                        ""Product"": [
                            {
                                ""MyName"": {
                                    ""CarName"": ""Car polish"",
                                    ""IsPublic"": ""True""
                                }
                            }
                        ]
                    },
                    ""MyName"": {
                        ""CustName"": ""Mr. Clouseau""
                    },
                    ""AddressLine1"": {
                        ""SomeAddr"": ""Hightstreet 13""
                    }
                }
            }
        }";

        RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);

        Client client = obj.Result.Client;
        foreach (Product product in client.ProductList)
        {
            Console.WriteLine(product.Name);
        }
        Console.WriteLine(client.Name);
        Console.WriteLine(client.AddressLine1);
    }
}

如您所见,解析的方式有点笨拙,所以我的问题是:

As you can see, the way the parsing is being done is a bit hacky, so my questions are:

  1. 我可以在不弄乱我的类的情况下将此解析合并到类中吗?
  2. 如果我的方法是可行的,我如何重新创建对象以便 ReadJson() 可以返回它(请参阅上面代码中的问号)
  3. 更上一层楼:如果客户端类有一个接受参数的构造函数(传递给基类),你会怎么做 2.(因为额外的嵌套级别会使事情复杂化,我相信)
  4. 如果这是错误的方式,我愿意接受建议

推荐答案

从您的问题和评论来看,您似乎有一些复杂的 JSON,您的目标是将其扁平化为更简单的类结构.但是您还有一些额外的限制:

From your question and comments it sounds like you have some complex JSON and your goal is to flatten it down into a simpler class structure. But you have some additional constraints:

  • 反序列化的目标类没有默认(无参数)构造函数.
  • 您想将 JSON 中的键映射到类中不同命名的属性.
  • 对于某些属性,您还想转换这些值(例如,将 true 转换为 false,反之亦然).
  • 您希望将所有映射逻辑放在一个地方,与类分开.

您可以使用自定义的JsonConverter.关键是将 JSON 数据加载到 JObject 在转换器内部.从那里你可以使用 SelectToken指定从 JObject 检索特定数据片段的路径.然后,您可以使用这些部分通过它们的非默认构造函数来构造您的对象.同时,您可以翻译任何需要它的值.

You can do all this with a custom JsonConverter. The key is to load the JSON data into a JObject inside the converter. From there you can use SelectToken to specify paths to retrieve specific pieces of data from the JObject. You can then use these pieces to construct your objects via their non-default constructors. At the same time you can translate any values that require it.

例如,假设您从问题中的 JSON 开始,并且您真正想要反序列化的类如下所示:

For example, let's say you are starting with the JSON in your question, and the classes you really want to deserialize to look like this:

public class Client
{
    public Client(string name, string addressLine1, List<Product> productList)
    {
        Name = name;
        AddressLine1 = addressLine1;
        ProductList = productList;
    }

    public List<Product> ProductList { get; set; }
    public string Name { get; set; }
    public string AddressLine1 { get; set; }
}

public class Product
{
    public Product(string name, bool isPrivate)
    {
        Name = name;
        IsPrivate = isPrivate;
    }

    public string Name { get; set; }
    public bool IsPrivate { get; set; }
}

这是一个处理反序列化的自定义转换器:

Here is a custom converter that will handle the deserialization:

class CustomConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Client);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);

        string name = (string)obj.SelectToken("Result.Client.MyName.CustName");
        string addressLine1 = (string)obj.SelectToken("Result.Client.AddressLine1.SomeAddr");
        List<Product> productList = obj.SelectToken("Result.Client.ProductList.Product")
            .Select(jt =>
            {
                string prodName = (string)jt.SelectToken("MyName.CarName");
                bool isPublic = string.Equals((string)jt.SelectToken("MyName.IsPublic"), "True", StringComparison.OrdinalIgnoreCase);
                return new Product(prodName, !isPublic);
            })
            .ToList();

        Client client = new Client(name, addressLine1, productList);
        return client;
    }

    public override bool CanWrite => false;

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

要使用转换器,您可以将 [JsonConverter] 属性添加到 Client 类,如下所示:

To use the converter, you can either add a [JsonConverter] attribute to the Client class like this:

[JsonConverter(typeof(CustomConverter))]
public class Client
{
   ...
}

或者您可以像这样将转换器作为参数传递给 JsonConvert.DeserializeObject():

Or you can pass the converter as a parameter to JsonConvert.DeserializeObject() like this:

Client client = JsonConvert.DeserializeObject<Client>(json, new CustomConverter());

这是一个工作演示:https://dotnetfiddle.net/EwtQHh

这篇关于从自定义 Json 转换器中操作 Json 字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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