Conversion from an absolute URL to relative
-
Hi,
Are there any method in Cocoa to convert an absolute URL to a relative URL
with a given base URL?
Satoshi,
-----------------------------------------------------
Satoshi Matsumoto <satoshi...>
816-5 Odake, Odawara, Kanagawa, Japan 256-0802
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hello...
It would probably be easiest to work with the urls as NSStrings,
using the NSURL methods that accept/return strings.
Then, you could do something like this:
NSString *baseURLString = @"http://www.base.com/url/";
NSString *absoluteURLString =
@"http://www.base.com/url/plus/other/stuff.html";
NSString *relativeURLString;
NSRange prefix = [absoluteURLString rangeOfString:baseURLString];
if (prefix.location == 0)
{
relativeURLString = [absoluteURLString
substringFromIndex:prefix.length];
}
else
{
/* base url was not found, or not at beginning of
absolute url */
relativeURLString = nil;
}
For the example URL strings above, the code should result in
relativeURLString containing the string @"plus/other/stuff.html",
which you could put back into an NSURL if you need to using it and
baseURLString.
Hope that helps,
Louis
> Hi,_______________________________________________
>
> Are there any method in Cocoa to convert an absolute URL to a relative URL
> with a given base URL?
>
> Satoshi,
> -----------------------------------------------------
> Satoshi Matsumoto <satoshi...>
> 816-5 Odake, Odawara, Kanagawa, Japan 256-0802
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Dear Louis,
Thank you for your kind information. It's very helpful.
But in following case, where absolute URLs are outside of base URL directory
baseURLString = @"http://www.base.com/url/"
absoluteURLString = @"http://www.base.com/img/image.jepg"
The result relativeURL should be @"../img/image.jepg"
I am going to write a method that can handle above cases...
Satoshi
on 04.3.10 4:24 PM, Louis C. Sacha at <subsLCS...> wrote:
> Hello...
>
> It would probably be easiest to work with the urls as NSStrings,
> using the NSURL methods that accept/return strings.
>
> Then, you could do something like this:
>
> NSString *baseURLString = @"http://www.base.com/url/";
> NSString *absoluteURLString =
> @"http://www.base.com/url/plus/other/stuff.html";
>
>
> NSString *relativeURLString;
>
> NSRange prefix = [absoluteURLString rangeOfString:baseURLString];
>
> if (prefix.location == 0)
> {
> relativeURLString = [absoluteURLString
> substringFromIndex:prefix.length];
> }
> else
> {
> /* base url was not found, or not at beginning of_______________________________________________
> absolute url */
> relativeURLString = nil;
> }
>
>
> For the example URL strings above, the code should result in
> relativeURLString containing the string @"plus/other/stuff.html",
> which you could put back into an NSURL if you need to using it and
> baseURLString.
>
>
> Hope that helps,
>
> Louis
>
>> Hi,
>>
>> Are there any method in Cocoa to convert an absolute URL to a relative URL
>> with a given base URL?
>>
>> Satoshi,
>> -----------------------------------------------------
>> Satoshi Matsumoto <satoshi...>
>> 816-5 Odake, Odawara, Kanagawa, Japan 256-0802
> _______________________________________________
> cocoa-dev mailing list | <cocoa-dev...>
> Help/Unsubscribe/Archives:
> http://www.lists.apple.com/mailman/listinfo/cocoa-dev
> Do not post admin requests to the list. They will be ignored.
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hello...
In order to work correctly for cases like
> baseURLString = @" http://www.base.com/url/ "
> absoluteURLString = @" http://www.base.com/img/image.jepg "
>
> The result relativeURL should be @"../img/image.jepg"
and others (where the last item in the base url is not a directory,
etc...), the code would have to be a bit more complex.
/* typed in mail, not tested, etc... */
- (NSString *)relativeURLStringForAbsoluteURLString:(NSString
*)absoluteURLString withBaseURLString:(NSString *)baseURLString
{
if ((baseURLString)&&(![baseURLString isEqualToString:@""])
{
/* make sure that baseURLString ends in a directory */
if (![[baseURLString
substringFromIndex:([baseURLString length] - 1)]
isEqualToString:@"/"])
{
/* note: doing this doesn't change the actual
string that was passed in, it changes the string that the method's
baseURLString pointer points to, and has no effect outside of this
method's scope */
baseURLString = [NSString
stringWithFormat:@"%@/",[baseURLString
stringByDeletingLastPathComponent]];
}
NSString *commonString = [absoluteURLString
commonPrefixWithString:baseURLString options:NSLiteralSearch];
if ((commonString)&&(![commonString isEqualToString:@""]))
{
/* make sure that the common url path ends in
a directory */
if (![[commonString
substringFromIndex:([commonString length] - 1)] isEqualToString:@"/"])
{
commonString = [NSString
stringWithFormat:@"%@/",[commonString
stringByDeletingLastPathComponent]];
}
NSString *remainderString;
if ([commonString
isEqualToString:absoluteURLString]) {remainderString = @"";}
else
{
NSRange commonRange =
[absoluteURLString rangeOfString:commonString];
remainderString = [absoluteURLString
substringFromIndex:commonRange.length];
}
/* add ../ to back up to parent directory as
many times as required */
while (![commonString isEqualToString:baseURLString])
{
baseURLString = [NSString
stringWithFormat:@"%@/",[baseURLString
stringByDeletingLastPathComponent]];
remainderString = [NSString
stringWithFormat:@"../%@",remainderString]];
}
return remainderString;
}
}
/* no baseURLString, empty base url, or base url does not match */
return absoluteURLString;
}
Please remember that this was typed up in mail and I can't test it at
the moment, so there may be errors either in typing or in logic. It
should at least give you a general idea of what you could do by
working with the strings to get the relative url, even if it doesn't
work perfectly (or at all).
Hope that helps,
Louis
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hello...
I knew I should have waited until I could test that code before posting it :)
It turns out that using the NSString method
stringByDeletingLastPathComponent on a url won't actually work, since
it causes the second slash after the colon in the url to be lost. For
example http://www.somesite.com/index.html turns into
http:/www.somesite.com and so the common prefix of the clipped
baseURLString and the absoluteURLString would end up being http:/
since the second slash was still present in the absoluteURLString but
not the baseURLString. That doesn't work too well when it's used to
figure out the relative url...
Also, if the urls for the absolute and base urls are from different
sites, the relative url returned should be the absolute url.
So here's an updated version, now that I've had a chance to test it
and make sure it basically works (although there might still be other
bugs floating around).
- (NSString *)relativeURLStringForAbsoluteURLString:(NSString
*)absoluteURLString withBaseURLString:(NSString *)baseURLString
{
if ((baseURLString)&&(![baseURLString isEqualToString:@""]))
{
/* make sure that baseURLString ends in a directory */
if (![[baseURLString
substringFromIndex:([baseURLString length] - 1)]
isEqualToString:@"/"])
{
unsigned endOfLastDirectoryIndex =
[baseURLString rangeOfString:@"/"
options:(NSLiteralSearch|NSBackwardsSearch)
range:NSMakeRange(0,[baseURLString length]-1)].location;
if (endOfLastDirectoryIndex != NSNotFound)
{baseURLString = [baseURLString
substringToIndex:(endOfLastDirectoryIndex+1)];}
else {baseURLString = @"";}
}
NSString *commonString = [absoluteURLString
commonPrefixWithString:baseURLString options:NSLiteralSearch];
if ((commonString)&&(![commonString isEqualToString:@""]))
{
/* make sure that the common url path ends in
a directory */
if (![[commonString
substringFromIndex:([commonString length] - 1)] isEqualToString:@"/"])
{
unsigned endOfLastDirectoryIndex =
[commonString rangeOfString:@"/"
options:(NSLiteralSearch|NSBackwardsSearch)
range:NSMakeRange(0,[commonString length]-1)].location;
if (endOfLastDirectoryIndex !=
NSNotFound) {commonString = [commonString
substringToIndex:(endOfLastDirectoryIndex+1)];}
else {commonString = @"";}
}
if (([commonString
length]>2)&&(![[commonString substringFromIndex:([commonString
length] - 2)] isEqualToString:@"//"]))
{
NSString *remainderString;
if ([commonString
isEqualToString:absoluteURLString]) {remainderString = @"";}
else
{
NSRange commonRange =
[absoluteURLString rangeOfString:commonString];
remainderString =
[absoluteURLString substringFromIndex:commonRange.length];
}
/* add ../ to back up to parent
directory as many times as required */
while (![commonString
isEqualToString:baseURLString])
{
unsigned truncateAfterIndex =
[baseURLString rangeOfString:@"/"
options:(NSLiteralSearch|NSBackwardsSearch)
range:NSMakeRange(0,[baseURLString length]-1)].location;
baseURLString = [baseURLString
substringToIndex:(truncateAfterIndex+1)];
remainderString = [NSString
stringWithFormat:@"../%@",remainderString];
}
return remainderString;
}
}
}
/* no baseURLString, empty base url, or base url does not match */
return absoluteURLString;
}
With apologies to digest readers who aren't interested, but still get
to scroll past my code twice :)
Louis
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hi, Louis
on 04.3.10 8:12 PM, Louis C. Sacha at <subsLCS...> wrote:
> So here's an updated version, now that I've had a chance to test it
> and make sure it basically works (although there might still be other
> bugs floating around).
Thank you, Louis!
I also wrote a NSString extension as follows. :-)
Although I am going to test it now.
- (NSString *)relativePathForBasePath:(NSString *)basePath
{
NSArray *myPathComponents = [self pathComponents];
NSArray *basePathComponents = [basePath pathComponents];
int commonIndex, index;
NSString *resutPath;
commonIndex = -1;
for( index=0; index < [basePathComponents count]; index++ )
{
if( ![[basePathComponents objectAtIndex:index]
isEqualToString:[myPathComponents objectAtIndex:index]] ) break;
commonIndex++;
}
if( commonIndex == -1 )
{
// another volume
resutPath = [NSString stringWithString:self];
}
else if( commonIndex == [basePathComponents count] -1 )
{
// in base directory
resutPath=[NSString stringWithString:@""];
for( index=commonIndex+1; index < [myPathComponents count]; index++ )
{
resutPath = [resutPath
stringByAppendingPathComponent:[myPathComponents objectAtIndex:index]];
}
}
else
{
// outside of base directory
resutPath=[NSString stringWithString:@""];
for( index=commonIndex; index< [basePathComponents count]-1; index++ )
{
resutPath=[resutPath stringByAppendingString:@"../"];
}
for( index=commonIndex+1; index < [myPathComponents count]; index++ )
{
resutPath = [resutPath
stringByAppendingPathComponent:[myPathComponents objectAtIndex:index]];
}
}
return resutPath;
}
-----------------------------------------------------
Satoshi Matsumoto <satoshi...>
816-5 Odake, Odawara, Kanagawa, Japan 256-0802
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.


