JSON. net: преобразование 1 объекта в 2 отдельных массива без родителя - с помощью JsonConverter - PullRequest
1 голос
/ 03 марта 2020

JSON. net: Как преобразовать / разбить 1 объект в 2 отдельных массива без родительского узла с JsonConverter ?

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;
        }
    }

К сожалению, структура TestClass и SymCollection не может быть изменена.


ОБНОВЛЕНИЕ 1 : одно из возможных решений, предложенное Павел Аниховский , частично ручная работа без 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);

1 Ответ

1 голос
/ 03 марта 2020

Вы можете попробовать переписать свой json, используя Json.Linq. Разобрать значение в JObject, затем перечислить SymCollection элементов (поскольку это массив), затем go через свойства каждого элемента и добавить каждое свойство в родительский элемент, используя Name и Value JProperty. Наконец, удалите SymCollection token

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 l oop является избыточным, вы можете получить только первое свойство каждого элемента SymCollection без использования al oop (если ты уверен в этом).

Приведенный выше код дает следующий вывод

{
  "Name": "Bus",
  "Type": "Vehicle",
  "ids": [
    0,
    1
  ],
  "weights": [
    100,
    50
  ]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...