都道府県と市区町村を取得するAppleScriptハンドラ


* 都道府県と市区町村、それぞれの名前とコードを取得
* 市区町村の取得には国土交通省土地情報システムの都道府県内市区町村一覧取得APIを使用


```AppleScript:prefecturesAndCities.scpt
use scripting additions
use framework "Foundation"

set prefectureFilterPredicate to current application's NSPredicate's predicateWithFormat_("name ENDSWITH %@", "府")
set prefectureArray to my prefectures(prefectureFilterPredicate)
log (prefectureArray's valueForKey:"name") as list
--> {"京都府", "大阪府"}

set address to current application's NSString's stringWithString:"東京都千代田区千代田1-1"

set prefectureFilterPredicate to current application's NSPredicate's predicateWithFormat_("%@ BEGINSWITH name", address)
set prefecture to my prefectures(prefectureFilterPredicate)'s firstObject()
log prefecture as record
--> {|id|:13, |name|:"東京都", romanName:"tokyo"}

set cityFilterPredicate to current application's NSPredicate's predicateWithFormat_("%@ BEGINSWITH name", address's substringFromIndex:(prefecture's |name|'s |length|))
set city to my cities(prefecture's |id|, cityFilterPredicate)'s firstObject()
log city as record
--> {|id|:"13101", |name|:"千代田区"}

on prefectures(filterPredicate)
	--require framework: Foundation
	set prefs to current application's NSArray's arrayWithArray:{{|id|:1, |name|:"北海道", romanName:"hokkaido"}, {|id|:2, |name|:"青森県", romanName:"aomori"}, {|id|:3, |name|:"岩手県", romanName:"iwate"}, {|id|:4, |name|:"宮城県", romanName:"miyagi"}, {|id|:5, |name|:"秋田県", romanName:"akita"}, {|id|:6, |name|:"山形県", romanName:"yamagata"}, {|id|:7, |name|:"福島県", romanName:"fukushima"}, {|id|:8, |name|:"茨城県", romanName:"ibaraki"}, {|id|:9, |name|:"栃木県", romanName:"tochigi"}, {|id|:10, |name|:"群馬県", romanName:"gunma"}, {|id|:11, |name|:"埼玉県", romanName:"saitama"}, {|id|:12, |name|:"千葉県", romanName:"chiba"}, {|id|:13, |name|:"東京都", romanName:"tokyo"}, {|id|:14, |name|:"神奈川県", romanName:"kanagawa"}, {|id|:15, |name|:"新潟県", romanName:"niigata"}, {|id|:16, |name|:"富山県", romanName:"toyama"}, {|id|:17, |name|:"石川県", romanName:"ishikawa"}, {|id|:18, |name|:"福井県", romanName:"fukui"}, {|id|:19, |name|:"山梨県", romanName:"yamanashi"}, {|id|:20, |name|:"長野県", romanName:"nagano"}, {|id|:21, |name|:"岐阜県", romanName:"gifu"}, {|id|:22, |name|:"静岡県", romanName:"shizuoka"}, {|id|:23, |name|:"愛知県", romanName:"aichi"}, {|id|:24, |name|:"三重県", romanName:"mie"}, {|id|:25, |name|:"滋賀県", romanName:"shiga"}, {|id|:26, |name|:"京都府", romanName:"kyoto"}, {|id|:27, |name|:"大阪府", romanName:"osaka"}, {|id|:28, |name|:"兵庫県", romanName:"hyogo"}, {|id|:29, |name|:"奈良県", romanName:"nara"}, {|id|:30, |name|:"和歌山県", romanName:"wakayama"}, {|id|:31, |name|:"鳥取県", romanName:"tottori"}, {|id|:32, |name|:"島根県", romanName:"shimane"}, {|id|:33, |name|:"岡山県", romanName:"okayama"}, {|id|:34, |name|:"広島県", romanName:"hiroshima"}, {|id|:35, |name|:"山口県", romanName:"yamaguchi"}, {|id|:36, |name|:"徳島県", romanName:"tokushima"}, {|id|:37, |name|:"香川県", romanName:"kagawa"}, {|id|:38, |name|:"愛媛県", romanName:"ehime"}, {|id|:39, |name|:"高知県", romanName:"kochi"}, {|id|:40, |name|:"福岡県", romanName:"fukuoka"}, {|id|:41, |name|:"佐賀県", romanName:"saga"}, {|id|:42, |name|:"長崎県", romanName:"nagasaki"}, {|id|:43, |name|:"熊本県", romanName:"kumamoto"}, {|id|:44, |name|:"大分県", romanName:"oita"}, {|id|:45, |name|:"宮崎県", romanName:"miyazaki"}, {|id|:46, |name|:"鹿児島県", romanName:"kagoshima"}, {|id|:47, |name|:"沖縄県", romanName:"okinawa"}}
	if filterPredicate = missing value then
		return prefs
	else
		return prefs's filteredArrayUsingPredicate:filterPredicate
	end if
end prefectures

on cities(prefectureID, filterPredicate)
	--require framework: Foundation
	--reference: http://www.land.mlit.go.jp/webland/api.html
	set citySearchURL to current application's NSURL's URLWithString:("http://www.land.mlit.go.jp/webland/api/CitySearch?area=" & prefectureID)
	set citySearchResult to my getJSONFromURL(citySearchURL)
	if not (citySearchResult's status's isEqualTo:"OK") then
		error "Error in handler 'cities()'"
	end if
	if filterPredicate = missing value then
		return citySearchResult's |data|
	else
		return citySearchResult's |data|'s filteredArrayUsingPredicate:filterPredicate
	end if
end cities

on getJSONFromURL(aURL)
	--require framework: Foundation
	set JSONData to my getDataFromURL(aURL)
	return my JSONFromData(JSONData)
end getJSONFromURL

on JSONFromData(JSONData)
	--require framework: Foundation
	set JSON to current application's NSJSONSerialization's JSONObjectWithData:JSONData options:(current application's NSJSONReadingMutableContainers) |error|:(missing value)
	if not (current application's NSJSONSerialization's isValidJSONObject:JSON) as boolean then
		error "Not JSON Data"
	end if
	return JSON
end JSONFromData

on getDataFromURL(requestURL)
	--require framework: Foundation
	set request to current application's NSURLRequest's requestWithURL:requestURL
	return my executeURLSessionTaskWithRequest(request)'s |data|
end getDataFromURL

on executeURLSessionTaskWithRequest(request)
	--require framework: Foundation
	--require method: URLSession:dataTask:didReceiveData:, URLSession:task:didCompleteWithError:
	
	--初期化
	global session, receivedData, dataTask, errorInURLSession
	set receivedData to current application's NSMutableData's alloc()'s init()
	set errorInURLSession to missing value
	
	--URLSessionからdata taskを作成
	try
		session
	on error number -2753
		set configuration to current application's NSURLSessionConfiguration's ephemeralSessionConfiguration()
		set session to current application's NSURLSession's sessionWithConfiguration:configuration delegate:(me) delegateQueue:(missing value)
	end try
	set dataTask to session's dataTaskWithRequest:request
	
	--taskを実行
	dataTask's resume()
	repeat while dataTask's state as integer = current application's NSURLSessionTaskStateRunning
		delay 0.1
	end repeat
	if errorInURLSession ≠ missing value then
		error errorInURLSession's localizedDescription as text number errorInURLSession's code as integer
	end if
	
	--受けたデータを返す
	return {task:dataTask, |data|:receivedData}
end executeURLSessionTaskWithRequest

on URLSession:session dataTask:task didReceiveData:aData
	global dataTask, receivedData
	set dataTask to task
	receivedData's appendData:aData
end URLSession:dataTask:didReceiveData:

on URLSession:session task:task didCompleteWithError:|error|
	global dataTask, errorInURLSession
	set dataTask to task
	set errorInURLSession to |error|
end URLSession:task:didCompleteWithError:
```



## 更新履歴

* 2018-08-26: 新規作成