views:

529

answers:

2

*I'm using yajl_JSON library to produce an NSDictionary from a JSON response for the bit.ly url shortening service.*

The JSON response:

{
  errorCode = 0;
  errorMessage = "";
  results = {
      "http://www.example.com/" = {
          hash = 4H5keM;
          shortKeywordUrl = "";
          shortUrl = "http://bit.ly/4BN4qV";
          userHash = 4BN4qV;
      };
  };
  statusCode = OK;
}

To clarify, "http://example.com" is not a child "results". And when parsed I have a 3 three nested NSDictionaries.

The problem is that "http://example.com" is arbitrary key. I want to access the keys data without knowing the key. Specifically, so I can get to the value for "shortUrl". How can this this be done effectively? Is there a way to make a keyPath that would be like this:

"results.*.shortUrl"

I have accomplished it by doing the following, but I presume this is not the way it is done:

 // Parse the JSON responce
 NSDictionary *jsonResponce = [data yajl_JSON];

 // Find the missing key
 NSString *missingKey = [[[jsonResponce valueForKeyPath:@"results"] allKeys] objectAtIndex:0];

 // Log the value for "shortURL"
 NSLog(@"It is : %@", [[[jsonResponce objectForKey:@"results"] valueForKeyPath:missingKey] objectForKey:@"shortUrl"]);

If I was using XML, it could be simple to do, which makes me believe I'm not using json/objective-c correctly.

I know it would be possible to store "example.com" in this situation when I make the request to Bit.ly, but... it would be good to know for the future...

Thanks.

+1  A: 

The NSDictionary method allValues returns an array of the values in a dictionary unattached from their keys, and Key-Value Coding for NSArrays produces an array of the given key's value for all the items in the array. So you can do [[jsonResponse valueForKeyPath:@"results.allValues.shortURL"] objectAtIndex:0] to get the shortURL.

Chuck
That doesn't return anything unfortunately as "shortURL" parent is not "results". "results" is the grandparent of "shortURL".
Ross
Oh, sorry, I misread the structure.
Chuck
The current version is fixed and should work, BTW.
Chuck
+1  A: 

Assuming you have an NSDictionary results = [jsonResponce objectForKey:@"results] which is this part of the dictionary:

{
    "http://www.example.com/" = {
          hash = 4H5keM;
          shortKeywordUrl = "";
          shortUrl = "http://bit.ly/4BN4qV";
          userHash = 4BN4qV;
    };
};

You can loop through all the keys in the dictionary:

NSString *shortURL = null;
for (id key in results) {
    NSDictionary* resultDict = [results objectForKey:key];
    shortURL = [resultDict objectForKey:@"shortURL"];
    NSLog(@"url: %@ shortURL: %@", key, shortURL);
}

Or you can just get all the values in the dictionary and pull out the first one:

NSDictionary* resultDict = [[results allValues] objectAtIndex:0];
NSString *shortURL = [resultDict objectForKey:@"shortURL"];

Or if you want the long URL too, use allKeys:

NSString *url = [[results allKeys] objectAtIndex:0]
NSDictionary* resultDict = [results objectForKey:url];
NSString *shortURL = [resultDict objectForKey:@"shortURL"];

(Note that you should actually check the length of the arrays returned by allKeys and allValues.)

Colin Gislason
thanks for the answer, but my problem is that I have three nested dictionaries and don't know the only key of the second (middle) dictionary. your solution only applies a single level dictionary.
Ross
That's because I assumed you had the middle dictionary already. I'll replace all the spots where I used 'jsonResponse' as the dictionary with 'results' to illustrate.
Colin Gislason