Ilan
Ilan

Reputation: 513

Finding specific values in JSON.NET with C#

I've been making a Minecraft launcher. I have a long JSON file that contains all the libraries required to launch one version. A sample of this code:

{
  "id": "1.6.2",
  "time": "2013-08-06T14:00:00+03:00",
  "releaseTime": "2013-07-05T16:09:02+03:00",
  "type": "release",
  "minecraftArguments": "--username ${auth_player_name} --session ${auth_session} --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}",
  "libraries": [
    {
      "name": "net.sf.jopt-simple:jopt-simple:4.5"
    },
    {
      "name": "com.paulscode:codecjorbis:20101023"
    },

So you can see that there is an array called libraries. I can query the values in "name" using a foreach quite fine, but sometimes this occurs in the json:

{
  "name": "org.lwjgl.lwjgl:lwjgl:2.9.0",
  "rules": [
    {
      "action": "allow"
    },
    {
      "action": "disallow",
      "os": {
        "name": "osx",
        "version": "^10\\.5\\.\\d$"
      }
    }
  ]
},

So as you can see, there is an array inside called rules. I need to find the value of name inside os inside rules. Anything I've tried came up with an exception and wouldn't work. This is my code at the moment for parsing the code:

    foreach (JToken lib in profilejsono["libraries"])
    {
        if ((lib["rules"][1]["os"].ToString() == "osx") || (lib["rules"][1]["os"].ToString() == "linux"))
        {
            availableLibs.Add(lib["name"].ToString());
        }
    }

The point of the code is not to add the library if it's for OSX or Linux (I'll add that functionality later). How do I do this?

Upvotes: 0

Views: 808

Answers (1)

keenthinker
keenthinker

Reputation: 7820

One possible solution to your problem is to generalize the check for the OS name (and make it independant of the rules node depth). I suppose you have some library objects, because you need to deserialize the JSON input string to some object. The following code gives you the library names only for library nodes that have rule nodes with os nodes with a specified name:

JSON Test-Input file lib1.json:

{
  "name": "lib1",
  "rules": [
    {
      "action": "allow"
    },
    {
      "action": "disallow",
      "os": {
        "name": "windows",
        "version": "^10\\.5\\.\\d$"
      }
    }
  ]
}

JSON Test-Input file lib2.json:

{
  "name": "lib2",
  "rules": [
    {
      "action": "allow"
    },
    {
      "action": "disallow",
      "os": {
        "name": "osx",
        "version": "^10\\.5\\.\\d$"
      }
    }
  ]
}

JSON Test-Input file lib3.json:

{
  "name": "lib3",
  "rules": [
    {
      "action": "allow"
    },
    {
      "action": "disallow",
      "os": {
        "name": "linux",
        "version": "^10\\.5\\.\\d$"
      }
    }
  ]
}

JSON Test-Input file lib4.json:

{
  "name": "lib4",
  "rules": [
    {
      "action": "allow"
    },
    {
      "action": "disallow"
    }
  ]
}

JSON helper objects describing the library node, needed to deserialize the JSON inputs:

// helper classes describing the library object (for the JSON deserialization)
public class Library
{
    public String Name { get; set; }
    public Rules[] Rules { get; set; }
}

public class Rules
{
    public String Action { get; set; }
    public Os Os { get; set; }
}

public class Os
{
    public String Name { get; set; }
    public String Version { get; set; }
}

Code for fetching only matching libraries:

var jsonInput = @"d:\temp\json.net\lib{0}.json";
try
{
    // load libraries / deserialize json
    var libraries = new List<Library>();
    Enumerable.Range(1, 4).ToList().ForEach(index => 
    {
        var json = File.ReadAllText(String.Format(jsonInput, index));
        libraries.Add(JsonConvert.DeserializeObject<Library>(json));
    });
    // OS names to check if present in the current rules
    var osNames = new List<String> { "osx", "linux" };
    // check each library
    foreach (var library in libraries)
    {
        // do we have rules?
        if (library.Rules.Length > 0)
        {
            // get all non-empty OS nodes
            var existingOsNodes = library.Rules.Where (r => r.Os != null).Select (r => r.Os).ToList();
            // check for allowed OS name
            var osIsPresent = existingOsNodes.Where (node => osNames.Contains(node.Name.ToLower())).Select (node => node.Name);
            if (osIsPresent.Any())
            {
                Console.WriteLine(library.Name);
            }
        }
    }
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

The output for the four given input files is:

lib2
lib3

Upvotes: 1

Related Questions