views:

1467

answers:

3

Are there any standard objects or functions to parse an NSURL's components? Clearly I could write one, but why re-invent the wheel?

[NSURL path] will return an NSString like "argX=x&argY=y&argZ=z" What I would rather get back is a dictionary populated with {@"argX" => @"x", @"argY" => @"y", @"argZ" = @"z"}

For the path, which returns a string like "/partA/partB/partC", I would rather get an array with the structure {[0] => @"partA", [1] => @"partB", [2] => @"partC"}

I realize this is a pretty specific ask, but it seems like something a lot of people would want...

EDIT - This is for iphoneOS! Apparently NSURL has different functions on Mac OS

+1  A: 

If you do decide to write one (I'm not sure there are existing methods of getting the components you want), you might want to use NSString's componentsSeparatedByString.

Jorge Israel Peña
Thanks, saved me a little bit of the work!
DougW
+2  A: 

You might want to look at pathComponents which returns an array of the components of the URL. Get more information here.

Mike
I don't believe this is available on the iphone version of the SDK. I should have clarified that I'm working on iphone OS.
DougW
[NSString pathComponents] is available in both the Cocoa and Cocoa Touch APIs. On the iPhone, you can imitate OS X 10.6's [NSURL pathComponents] with [[NSURL path] pathComponents].
Jarret Hardie
Ah perfect, that's what I was looking for, for the path portion at least!
DougW
Apple docs for [NSString pathComponents] state: "Note that this method only works with file paths (not, for example, string representations of URLs)."
Jason Moore
+2  A: 

Alright, I got antsy and wrote a solution for extending NSString through Categories. I haven't tested this yet, but if you want to use it, go for it.

@interface NSString (ParseCategory)
- (NSMutableDictionary *)explodeToDictionaryInnerGlue:(NSString *)innerGlue outterGlue:(NSString *)outterGlue;
@end

@implementation NSString (ParseCategory)

- (NSMutableDictionary *)explodeToDictionaryInnerGlue:(NSString *)innerGlue outterGlue:(NSString *)outterGlue {
    // Explode based on outter glue
    NSArray *firstExplode = [self componentsSeparatedByString:outterGlue];
    NSArray *secondExplode;

    // Explode based on inner glue
    NSInteger count = [firstExplode count];
    NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithCapacity:count];
    for (NSInteger i = 0; i < count; i++) {
     secondExplode = [(NSString *)[firstExplode objectAtIndex:i] componentsSeparatedByString:innerGlue];
     if ([secondExplode count] == 2) {
      [returnDictionary setObject:[secondExplode objectAtIndex:1] forKey:[secondExplode objectAtIndex:0]];
     }
    }

    return returnDictionary;
}

@end

It's called like this:

NSMutableDictionary *parsedQuery = [[myNSURL query] explodeToDictionaryInnerGlue:@"=" outterGlue=@"&"]

For parsing the path portion of the NSURL (ie @"/partA/partB/partC"), just call this:

NSArray *parsedPath = [[nyNSURL path] componentsSeperatedByString:@"/"];

Be aware that parsedPath[0] will be an empty string because of the leading /!

EDIT - Here is a Category extension to NSURL for your usage pleasure. It strips the initial "/" so you don't have an empty 0 index.

@implementation NSURL (ParseCategory)

- (NSArray *)pathArray {
    // Create a character set for the slash character
    NSRange slashRange;
    slashRange.location = (unsigned int)'/';
    slashRange.length = 1;
    NSCharacterSet *slashSet = [NSCharacterSet characterSetWithRange:slashRange];

    // Get path with leading (and trailing) slashes removed
    NSString *path = [[self path] stringByTrimmingCharactersInSet:slashSet];

    return [path componentsSeparatedByCharactersInSet:slashSet];
}

- (NSDictionary *)queryDictionary {
    NSDictionary *returnDictionary = [[[[self query] explodeToDictionaryInnerGlue:@"=" outterGlue:@"&"] copy] autorelease];
    return returnDictionary;
}

@end
DougW
Not sure why someone down-voted this... that'll teach me to share code I guess? I wouldn't really mind if you'd left a comment, but I'll just assume you're a random troll. Hi troll.
DougW
Thanks, this works fine for me. Note that you may need to URL-decode your individual query string values as well. I am using the following code for this, first to take care of percent-escapes, then to replace "+" with space, which the first one unfortunately doesn't do:[[value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:@"+" withString:@" "]
Mirko Froehlich
Very welcome. And yes, I left matters of encoding/decoding out of these functions.
DougW