0

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?

6
  • Would you share the exact exception that you get? Commented Jan 19, 2014 at 10:35
  • System.NullReferenceException (Object reference not set to an instance of an object. Commented Jan 19, 2014 at 10:41
  • You get this error because the way you try to reach to the ["os"] value. The foreach loop is returning each Jtoken but in fact only one item will return value for lib["rules"][1]["os"] otherwise you get null because this item just don't have the property "os". Commented Jan 19, 2014 at 10:45
  • 1
    There are many ways to manage this but the easiest one is just to make some additional check if lib["rules"].count >= 2, because you want the second element which has index [1] then, check if it has "os" property and so on... I don't tell it's the best way, but just to get you on the right track.. Commented Jan 19, 2014 at 10:48
  • 1
    My suggestion is to post new question with your working example no matter how bad you think it is and ask for assistance on improving it. In this question you find out why you get this error at first place, if I were you I would ask another question for the best way to deal with this case. Commented Jan 19, 2014 at 11:50

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

6 Comments

The problem is the general libraries don't have a rules element, only `name.
Soo how can you check for something if it is not present? Please explanation the matter more thoroughly and give more examples in your question.
What I did was check for an ArgumentNullException, which means it didn't find the specified element. Thus, it's fine. Otherwise, if it does find the rules element, it just does nothing.
The code from my answer works correctly in every situation you described (no matter what node is present and missing). Have you tried it out to see if it works for you?
No I haven't because I have JSON.NET, so most of your code is irrelevant.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.