2

I have a JSON file that has a property called craftingrequirements. This property can be an object or an array, what is the best way to process data in such a case?

Currently I have set the type to object for the property because otherwise there would be an error.

"weapon": [
    {
        "@uniquename": "T3_2H_QUARTERSTAFF",
        "craftingrequirements": [
            {
              "@silver": "0",
              "@time": "5",
              "@craftingfocus": "16085",
            },
            {
              "@silver": "0",
              "@time": "5",
              "@craftingfocus": "16085"
            }
        ]
    },
    {
        "@uniquename": "T6_2H_QUARTERSTAFF_AVALON",
        "craftingrequirements": {
          "@silver": "0",
          "@time": "1",
          "@craftingfocus": "980"
        }
    }
]

That didn't work either..

var craftingRequirement = equipmentItem.CraftingRequirements as CraftingRequirements;

if (craftingRequirement == null)
{
     var craftingRequirements = equipmentItem.CraftingRequirements as List<CraftingRequirements>;

}
if (equipmentItem.CraftingRequirements is CraftingRequirements)
{
} 
else if (equipmentItem.CraftingRequirements is List<CraftingRequirements>)
{
}

I work with .net / C# and haven't found a good solution yet.

5
  • comes the json from external (structure is out of your control)? Commented Jan 10, 2022 at 11:17
  • What library are you using for deserialization? I'd suggest defining CraftingRequirements as List in your c# classes. Then during deserialization check whether that property is an array or an object. If it's an array, you don't need to do anything. If it's an object, place that object in the CraftingRequirements List. So in your c# code you can always be sure that CraftingRequirements is a List, even if it sometimes only has one element. Commented Jan 10, 2022 at 11:26
  • @dba Yes, externally, unfortunately I have no control over it. Commented Jan 10, 2022 at 11:34
  • @derpirscher I'm using the System.Text.Json.JsonSerializer. How exactly do I do this, is there any further information? Do I have to set something in the JsonSerializerOptions for this? Commented Jan 10, 2022 at 11:37
  • 1
    I've never done it with System.Text.Json. But this should be a starting point learn.microsoft.com/en-us/dotnet/standard/serialization/… Unfortunately it's not just fiddling around with some options ... Commented Jan 10, 2022 at 11:39

2 Answers 2

1

add the Nuget-Package 'Newtonsoft.Json' to your project and try this. You propably need some fine tuning, but you should get the idea.

using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;

namespace ConsoleApp1
{
  class Program
  {
    static void Main(string[] args)
    {
      string json = @"{
'weapon': [
{
        '@uniquename': 'T3_2H_QUARTERSTAFF',
        'craftingrequirements': [
            {
          '@silver': '0',
              '@time': '5',
              '@craftingfocus': '16085',
            },
            {
          '@silver': '0',
              '@time': '5',
              '@craftingfocus': '16085'
            }
        ]
    },
    {
        '@uniquename': 'T6_2H_QUARTERSTAFF_AVALON',
        'craftingrequirements': {
          '@silver': '0',
          '@time': '1',
          '@craftingfocus': '980'
        }
      }
]
    }";


       JObject o = JObject.Parse(json);

      foreach (var w in o["weapon"])
      {
        var r2 = w["craftingrequirements"];
        if (r2 is JArray)
        {
          var res = JsonConvert.DeserializeObject<CraftingRequirements[]>(r2.ToString ().Replace("@", "") );
        }
        else
        {
          var res = JsonConvert.DeserializeObject<CraftingRequirements>(r2.ToString().Replace("@", ""));
        }
      }
    }
  }

  public class CraftingRequirements
  {
    public string silver { get; set; }
    public string time { get; set; }
    public string craftingfocus { get; set; }
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Only for those who care. There were other nested objects and arrays.

This is my current solution that works.

Maybe someone can do something with it, then just needs to be adjusted.

public class CraftingRequirementsToCraftingRequirementsList : JsonConverter<List<CraftingRequirements>>
{
    public override List<CraftingRequirements> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject && reader.TokenType != JsonTokenType.StartArray)
        {
            throw new JsonException("JSON payload expected to start with StartObject or StartArray token.");
        }

        var craftingRequirements = new List<CraftingRequirements>();
        
        try
        {
            craftingRequirements = reader.TokenType switch
            {
                JsonTokenType.StartArray => SetCraftingRequirementsArray(ref reader),
                JsonTokenType.StartObject => SetCraftingRequirementsObject(ref reader),
                _ => craftingRequirements
            };
        }
        catch (Exception)
        {
            return craftingRequirements;
        }

        return craftingRequirements;
    }

    public override void Write(Utf8JsonWriter writer, List<CraftingRequirements> value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }


    private static List<CraftingRequirements> SetCraftingRequirementsArray(ref Utf8JsonReader reader)
    {
        var craftingRequirements = new List<CraftingRequirements>();
        var craftingRequirement = new CraftingRequirements();
        var startDepth = reader.CurrentDepth;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndArray && reader.CurrentDepth == startDepth)
            {
                return craftingRequirements;
            }

            if (reader.TokenType == JsonTokenType.StartObject)
            {
                craftingRequirement = new CraftingRequirements();
            }

            if (reader.TokenType == JsonTokenType.EndObject)
            {
                craftingRequirements.Add(craftingRequirement);
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();

                switch (propertyName)
                {
                    case "@silver":
                        reader.Read();
                        craftingRequirement.Silver = reader.GetString();
                        break;
                    case "@time":
                        reader.Read();
                        craftingRequirement.Time = reader.GetString();
                        break;
                    case "@craftingfocus":
                        reader.Read();
                        craftingRequirement.CraftingFocus = reader.GetString();
                        break;
                    case "craftresource":
                        reader.Read();
                        craftingRequirement.CraftResource = reader.TokenType switch
                        {
                            JsonTokenType.StartArray => SetCraftResourceArray(ref reader),
                            JsonTokenType.StartObject => SetCraftResourceObject(ref reader),
                            _ => craftingRequirement.CraftResource
                        };
                        break;
                    case "@swaptransaction":
                        reader.Read();
                        craftingRequirement.SwapTransaction = reader.GetString();
                        break;
                    case "playerfactionstanding":
                        reader.Read();
                        craftingRequirement.PlayerFactionStanding = SetPlayerFactionStanding(ref reader);
                        break;
                    case "currency":
                        reader.Read();
                        craftingRequirement.Currency = SetCurrency(ref reader);
                        break;
                    case "@amountcrafted":
                        reader.Read();
                        craftingRequirement.AmountCrafted = reader.GetString();
                        break;
                    case "@forcesinglecraft":
                        reader.Read();
                        craftingRequirement.ForceSingleCraft = reader.GetString();
                        break;
                }
            }
        }

        return craftingRequirements;
    }

    private static List<CraftingRequirements> SetCraftingRequirementsObject(ref Utf8JsonReader reader)
    {
        var craftingRequirements = new List<CraftingRequirements>();
        var craftingRequirement = new CraftingRequirements();
        var startDepth = reader.CurrentDepth;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == startDepth)
            {
                craftingRequirements.Add(craftingRequirement);
                return craftingRequirements;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();

                switch (propertyName)
                {
                    case "@silver":
                        reader.Read();
                        craftingRequirement.Silver = reader.GetString();
                        break;
                    case "@time":
                        reader.Read();
                        craftingRequirement.Time = reader.GetString();
                        break;
                    case "@craftingfocus":
                        reader.Read();
                        craftingRequirement.CraftingFocus = reader.GetString();
                        break;
                    case "craftresource":
                        reader.Read();
                        craftingRequirement.CraftResource = reader.TokenType switch
                        {
                            JsonTokenType.StartArray => SetCraftResourceArray(ref reader),
                            JsonTokenType.StartObject => SetCraftResourceObject(ref reader),
                            _ => craftingRequirement.CraftResource
                        };
                        break;
                    case "@swaptransaction":
                        reader.Read();
                        craftingRequirement.SwapTransaction = reader.GetString();
                        break;
                    case "playerfactionstanding":
                        reader.Read();
                        craftingRequirement.PlayerFactionStanding = SetPlayerFactionStanding(ref reader);
                        break;
                    case "currency":
                        reader.Read();
                        craftingRequirement.Currency = SetCurrency(ref reader);
                        break;
                    case "@amountcrafted":
                        reader.Read();
                        craftingRequirement.AmountCrafted = reader.GetString();
                        break;
                    case "@forcesinglecraft":
                        reader.Read();
                        craftingRequirement.ForceSingleCraft = reader.GetString();
                        break;
                }
            }
        }

        return craftingRequirements;
    }

    private static List<CraftResource> SetCraftResourceArray(ref Utf8JsonReader reader)
    {
        var craftResources = new List<CraftResource>();
        var craftResource = new CraftResource();
        var startDepth = reader.CurrentDepth;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndArray && reader.CurrentDepth == startDepth)
            {
                return craftResources;
            }

            if (reader.TokenType == JsonTokenType.StartObject)
            {
                craftResource = new CraftResource();
            }

            if (reader.TokenType == JsonTokenType.EndObject)
            {
                craftResources.Add(craftResource);
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();

                switch (propertyName)
                {
                    case "@uniquename":
                        reader.Read();
                        craftResource.UniqueName = reader.GetString();
                        break;
                    case "@count":
                        reader.Read();
                        if (int.TryParse(reader.GetString(), out var count))
                        {
                            craftResource.Count = count;
                            break;
                        }
                        craftResource.Count = 0;
                        break;
                    case "@maxreturnamount":
                        reader.Read();
                        craftResource.MaxReturnAmount = reader.GetString();
                        break;
                    case "@enchantmentlevel":
                        reader.Read();
                        craftResource.EnchantmentLevel = reader.GetString();
                        break;
                }
            }
        }

        return craftResources;
    }

    private static List<CraftResource> SetCraftResourceObject(ref Utf8JsonReader reader)
    {
        var craftResources = new List<CraftResource>();
        var newCraftResource = new CraftResource();
        var startDepth = reader.CurrentDepth;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == startDepth)
            {
                craftResources.Add(newCraftResource);
                return craftResources;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();

                switch (propertyName)
                {
                    case "@uniquename":
                        reader.Read();
                        newCraftResource.UniqueName = reader.GetString();
                        break;
                    case "@count":
                        reader.Read();
                        if (int.TryParse(reader.GetString(), out var count))
                        {
                            newCraftResource.Count = count;
                            break;
                        }
                        newCraftResource.Count = 0;
                        break;
                    case "@maxreturnamount":
                        reader.Read();
                        newCraftResource.MaxReturnAmount = reader.GetString();
                        break;
                    case "@enchantmentlevel":
                        reader.Read();
                        newCraftResource.EnchantmentLevel = reader.GetString();
                        break;
                }
            }
        }

        return craftResources;
    }

    private static PlayerFactionStanding SetPlayerFactionStanding(ref Utf8JsonReader reader)
    {
        var playerFactionStanding = new PlayerFactionStanding();
        var startDepth = reader.CurrentDepth;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == startDepth)
            {
                return playerFactionStanding;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();
                switch (propertyName)
                {
                    case "@faction":
                        reader.Read();
                        playerFactionStanding.Faction = reader.GetString();
                        break;
                    case "@minstanding":
                        reader.Read();
                        playerFactionStanding.MinStanding = reader.GetString();
                        break;
                }
            }
        }

        return playerFactionStanding;
    }
    
    private static Currency SetCurrency(ref Utf8JsonReader reader)
    {
        var currency = new Currency();
        var startDepth = reader.CurrentDepth;

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject && reader.CurrentDepth == startDepth)
            {
                return currency;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();
                switch (propertyName)
                {
                    case "@uniquename":
                        reader.Read();
                        currency.UniqueName = reader.GetString();
                        break;
                    case "@amount":
                        reader.Read();
                        currency.Amount = reader.GetString();
                        break;
                }
            }
        }

        return currency;
    }
}

1 Comment

No doubt this is the most efficient solution, however must be a nightmare to maintain. Your question helped me greatly, thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.