Click here to Skip to main content
15,887,267 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I have a JSON file which has an array of channels for a fixture. But if that fixture has multiple cells, some of the channels need to be repeated. My JSON file does this by having an array of each cell, and then another array of the channels that need to be repeated for each cell. These two arrays are inside an array inside the main channels array. I need a way to check if the main channels array has another array inside to determine whether the fixture has multiple cells or not. I cannot change the JSON file since it is coming from another source and I want the fixture files to be easily updateable.

This is my JSON:

{
      "name": "16: Effect RGB",
      "channels": [
        "Dimmer Master",
        "Strobe Master",
        "Programs",
        "Program Speed",
        "Program Fade Time",
        "Program Direction",
        "Program Group Size",
        "Group Offset",
        "Restart Program",
        {
          "insert": "matrixChannels",
          "repeatFor": [
            "Effect Color 1",
            "Effect Color 2",
            "Effect Color 3",
            "Effect Color 4"
          ],
          "channelOrder": "perPixel",
          "templateChannels": [
            "Red $pixelKey",
            "Green $pixelKey",
            "Blue $pixelKey"
          ]
        }
      ]
    },


What I have tried:

I'm unsure really how to check this in C#. I can get it to check how many items are in the main channels array but then obviously when it comes to the array within the channels array, it spits out an error. Any help would be appreciated! Cheers!
Posted
Updated 12-Nov-19 7:04am
Comments
Richard MacCutchan 9-Nov-19 5:41am    
"it spits out an error."
What is "it", and what is the error?
Member 14647867 9-Nov-19 7:59am    
Sorry this is the error: Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: {. Path 'modes[15].channels[8]', line 1666, position 9.'
Richard MacCutchan 9-Nov-19 8:21am    
Assuming that is actually: {. Path 'modes[15].channels[8]' then either the full stop after the opening brace, or the single quote before modes is chcharacter 9. I suspect neither of them belong in a JSON string.

Normally I would desalinize the JSON string into a C# model and use C# to do this, using Newton

Newton Json -Deserialize an Object[^]


If you dont want to do this and would rather use the JSON itself I would have a look at this

Get values from JSON object[^]
 
Share this answer
 
Comments
Richard MacCutchan 9-Nov-19 9:46am    
See comments above, OP is already using NewtonSoft.
Member 14647867 9-Nov-19 11:07am    
The issue is here that I have arrays within arrays within arrays and I need to check the type to see if it is an object or an array
Richard MacCutchan 9-Nov-19 11:15am    
Newtonsoft will do that for you. Your problem is that the JSON text contains invalid characters so the parsing fails.
Simon_Whale 9-Nov-19 15:43pm    
I've checked the sample that you gave above in an online Json validator (https://jsonlint.com) and it returned no errors. So I think you will need to review the models that you are parsing into.
The problem is that your channels array contains a mixture of strings and objects. Javascript doesn't have a problem with that, because it's loosely-typed. But C# is a strongly-typed language, and doesn't have a native representation of something that can be either one type or another.

You could potentially use LINQ to JSON[^] to access the data in a loosely-typed manner.

Otherwise, you're going to need a JsonConverter. For example:
C#
public class ChannelData
{
    public string Insert { get; set; }
    public string[] RepeatFor { get; set; }
    public string ChannelOrder { get; set; }
    public string[] TemplateChannels { get; set; }
}

[JsonConverter(typeof(ChannelConverter))]
public class Channel
{
    public string Value { get; set; }
    public ChannelData Data { get; set; }
}

public class ChannelConverter : JsonConverter
{
    public override bool CanRead => true;
    public override bool CanWrite => true;
    public override bool CanConvert(Type objectType) => objectType == typeof(Channel);
    
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        switch (token.Type)
        {
            case JTokenType.Null:
            {
                return null;
            }
            case JTokenType.String:
            {
                return new Channel { Value = (string)token };
            }
            case JTokenType.Object:
            {
                return new Channel { Data = token.ToObject<ChannelData>() };
            }
            default:
            {
                throw new NotSupportedException();
            }
        }
    }
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        switch (value)
        {
            case null:
            {
                writer.WriteNull();
                break;
            }
            case Channel c when c.Value is string s:
            {
                writer.WriteValue(s);
                break;
            }
            case Channel c when c.Data is ChannelData data:
            {
                serializer.Serialize(writer, data);
                break;
            }
            case Channel:
            {
                writer.WriteNull();
                break;
            }
            default:
            {
                throw new NotSupportedException();
            }
        }
    }
}

public class Fixture
{
    public string Name { get; set; }
    public Channel[] Channels { get; set; }
}
With that in place, your sample JSON will deserialize correctly to a Fixture object. You can also reserialize it to produce the same output.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900