【问题标题】:JSON.net: converting 1 object into 2 separate arrays without a parent – with JsonConverterJSON.net:将 1 个对象转换为 2 个没有父对象的单独数组 - 使用 JsonConverter
【发布时间】:2020-03-03 14:35:05
【问题描述】:

JSON.net:如何使用 JsonConverter 在没有父节点的情况下将 1 个对象 转换/拆分为 2 个单独的数组 em>?

JSON - 实际

{"Name":"Bus",
 "Type":"Vehicle",
 "SymCollection":[
    {"ids":[0,1]},
    {"weights":[100,50]}
]}

JSON - 预期

{"Name":"Bus",
 "Type":"Vehicle",
 "ids":[0,1],
 "weights":[100,50]
}

C# – 源对象(无法更改)

class TestClass
{
    public string Name;
    public string Type;
    public SymCollection SymCollection;
}

[JsonConverter(typeof(SymCollectionConverter))]
class SymCollection
{
    public int[] Ids;
    public int[] Weights;
}

C# – JsonConverter我该如何改变它?

class SymCollectionConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            SymCollection inputContainer = (SymCollection)value;

            // Need to delete next line – do not need any parent node.
            writer.WriteStartArray();


            writer.WriteStartObject();
            writer.WritePropertyName("ids");
            writer.WriteStartArray();
            foreach (var id in inputContainer.Ids)
            {
                writer.WriteValue(id);
            }
            writer.WriteEndArray();
            writer.WriteEndObject();


            writer.WriteStartObject();
            writer.WritePropertyName("weights");
            writer.WriteStartArray();
            foreach (var weight in inputContainer.Weights)
            {
                writer.WriteValue(weight);
            }
            writer.WriteEndArray();
            writer.WriteEndObject();


            // So, and delete next line too.
            writer.WriteEndArray();

        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override bool CanConvert(Type objectType)
        {
            return typeof(SymCollection) == objectType;
        }
    }

很遗憾,TestClassSymCollection 的结构无法更改。


更新 1Pavel Anikhouski 提出的一种可能的解决方案,部分手工制作,没有 JsonConverter

class TestClass
{
    public string Name;
    public string Type;

    [JsonIgnore]// Ignore and process it manually.
    public SymCollection SymCollection;

    public string ToJson()
    {
        // --> MAIN ATTENTION HERE <

        // Create JSON without SymCollection.
        var resultJObject = JObject.FromObject(this);

        // Add missing IDs and weights.
        var symbolIdsAndWeights = SymCollection.GetIdsAndWeightsJTokens();
        resultJObject.Add(symbolIdsAndWeights.ids);
        resultJObject.Add(symbolIdsAndWeights.weights);

        // Convert to string.
        string resultJson = resultJObject.ToString(Formatting.None);
        return resultJson;
    }


}

[JsonConverter(typeof(SymCollectionConverter))]
class SymCollection
{
    public int[] Ids;
    public int[] Weights;

    public (JToken ids, JToken weights) GetIdsAndWeightsJTokens()
    {
        JTokenWriter idsWriter = new JTokenWriter();
        idsWriter.WriteStartObject();
        idsWriter.WritePropertyName("ids");
        idsWriter.WriteStartArray();
        foreach (var id in Ids)
        {
            idsWriter.WriteValue(id);
        }
        idsWriter.WriteEndArray();
        idsWriter.WriteEndObject();

        JTokenWriter weightsWriter = new JTokenWriter();
        weightsWriter.WriteStartObject();
        weightsWriter.WritePropertyName("weights");
        weightsWriter.WriteStartArray();
        foreach (var weight in Weights)
        {
            weightsWriter.WriteValue(weight);
        }
        weightsWriter.WriteEndArray();
        weightsWriter.WriteEndObject();


        return (idsWriter.Token.First, weightsWriter.Token.First);

    }
}

以及用法为:

TestClass testObject = new TestClass();
string resultJsonStr = testObject.ToJson();
Console.WriteLine(resultJsonStr);

【问题讨论】:

  • 您是否认为JsonConverter 只是一个选项? Json.Linq 对你有意义吗?
  • 从预期的json 中删除最后一行的]
  • @Sajid 谢谢,已修复!
  • @PavelAnikhouski 请您发布一个如何使用 LINQ 修复它的简单示例? TestClass 背后的真正类是巨大的,所以只修复 SymCollection 会非常好。
  • @OlegZarevennyi 我已经添加了答案,请看一下

标签: c# json serialization json.net


【解决方案1】:

您可以尝试使用Json.Linq 重写您的json。将值解析为JObject,然后枚举SymCollection 项(因为它是一个数组),然后使用NameJPropertyNameValue 遍历每个项属性并将每个属性添加到父项。最后移除SymCollection令牌

var jObject = JObject.Parse(json);

foreach (JObject item in jObject["SymCollection"])
{
    foreach (var property in item.Properties())
    {
        jObject.Add(property.Name, property.Value);
    }
}

jObject.Remove("SymCollection");
var result = jObject.ToString();

也许,内部for 循环是多余的,您可以在不使用循环的情况下仅获得每个SymCollection 项目的第一个属性(如果您确定的话)。

上面的代码产生以下输出

{
  "Name": "Bus",
  "Type": "Vehicle",
  "ids": [
    0,
    1
  ],
  "weights": [
    100,
    50
  ]
}

【讨论】:

  • 老实说,我希望有更好更简单的方法,但它有助于解决这个问题。从某种意义上说,它是半手工制作的。我已根据您对我的问题的回答添加了解决方案(请参阅:更新 1)。
  • @OlegZarevennyi 很好的解决方案!但就我个人而言,我想避免混淆JsonConverterJson.Linq。您可以轻松地将JToken/JObject 转换为特定类型的实例并返回。无论如何,一切都取决于您的要求和现有的代码库
猜你喜欢
  • 2019-02-12
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 2020-09-09
  • 2013-10-20
相关资源
最近更新 更多