NSURL のクエリ文字列を解析する
SPECIAL
NSURL のクエリ文字列を解析する
NSURL で、たとえば "http://xxx.xxx.xx/f/p1.html?n1=v1&n2=v2" というような URL を扱っていたとします。
このときの NSURL の主要なプロパティには、次のように値が設定されます。
scheme | http |
---|---|
host | xxx.xxx.xx |
path | /f/p1.html |
query | n1=v1&n2=v2 |
パス文字列を NSURL に変換する
そもそも、パス文字列 "http://xxx.xxx.xx/f/p1.html?n1=v1&n2=v2" を NSURL に変換するには、NSURL の initWithString: メソッドを使います。
NSURL* url = [[NSURL alloc] initWithString:"http://xxx.xxx.xx/f/p1.html?n1=v1&n2=v2"];
こうすることで、これらの要素が解析されて NSURL で扱えるようになります。
このとき、該当箇所が指定されていない場合には、そのプロパティは nil になります。
たとえば "?" を含むそれ以降がない場合は query が nil になります。"?" がある場合は query は空文字です。また、"://" が無い場合は scheme と host が nil になり、path から始まるものとされます。
他にも "http:///" というようにすると、host が空文字になり、path が "/" になります。
path の階層を解析する
path プロパティの階層構造を調べたい場合は、NSString の pathComponents プロパティを参照します。
たとえば、さきほどの NSURL の path の階層を解析したい場合は、次のようにすることで直ぐに NSString 型の配列として取得できます。
NSArray* path = [url.path pathComponents];
こうすることで、パスが絶対パス指定なら最初の要素が "/" になり、それ以降にパスの各階層が設定されます。相対パス指定の場合は、最初の要素からパスの各階層が入れられます。
たとえば、さきほどの NSURL であれば、具体的に次の値が設定されます。
path[0] | / |
---|---|
path[1] | f |
path[2] | p1.html |
パス文字列の扱いについては NSString でパス文字列を操作する でも触れています。
query 文字列を NSDictionary に変換する
"?" を挟んで指定されるクエリ文字列は、通常、"名前=値" という書式で、複数の名前と値のセットが "&" で連結されて記述されています。
これを、扱いやすいように NSDictionary に変換してみます。
// クエリ文字列を NSDictionary に変換するメソッドを実装します。
+ (NSDictionary*)dictionaryFromQueryString:(NSString *)query
{
// クエリ文字列が設定されている場合だけ、解析処理をします。
if (query)
{
// 解析しながら、名前と値をここに蓄えて行きます。
NSMutableDictionary* result = [[NSMutableDictionary alloc] init];
// クエリ文字列を "&" で分割して、ひとつひとつの "名前=値" の組に分解します。
NSArray* parameters = [query componentsSeparatedByString:@"&"];
for (NSString* parameter in parameters)
{
// "&" で区切られた文字列が、空文字ではないものを解析します。
if (parameter.length > 0)
{
// 名前と値を分解します。
NSArray* elements = [parameter componentsSeparatedByString:@"="];
// 名前は UTF8 でエンコードされているものとしてデコードします。
id key = [elements[0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// 値があればそれを UTF8 でデコードして取得します。名前だけで値の指定が無い場合は、ここでは値を @YES とみなします。
id value = (elements.count == 1 ? @YES : [elements[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]);
// 取得した名前と値を保存します。重複は考慮していません。
[result setObject:value forKey:key];
}
}
// 取得した値と名前の組を、読み取り専用のインスタンスで返します。
return [result copy];
}
else
{
// クエリ文字列が nil だった場合は、結果も nil を返します。
return nil;
}
}
このようなコードを書くことで、クエリ文字列を扱いやすくなりました。
今回の例では、クエリ文字列は "n1=v1&n2=v2" なので、result[@"n1"] と result[@"n2"] でそれぞれ、"v1" と "v2" という値を取得できます。
[ もどる ]