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" という値を取得できます。

[ もどる ]