Google Apps Scriptでマイマップデータを取得する【GAS】
以前、Google Apps ScriptでスプレッドシートデータをGoogle Earthからのリクエストに応じてネットワークリンクを生成しデータを返す仕組みを作りました。一方、GoogleマイマップはKMLを出力出来るのですが、マイマップデータのバックアップを取りたいと思っても、KML出力しか無い為、データで管理したい場合、ちょっと困ります。
ということで、今回は逆パターンのマイマップのデータをスプレッドシートに書き出して管理する手法をまとめました。
今回利用するスプレッドシート
- マイマップデータを取得する - Google Spreadsheet
- 八丈島観光スポットMap - Googleマイマップ
今回は昔作ったマイマップデータを取得してスプレッドシートに出力します。KMZ形式で取得した場合は、一旦解凍して中に入ってるdoc.kmlを取得する必要があるため、今回は手軽なKML形式の方で取得します。
KMZ形式の場合独自アイコン等も取得出来るので個人的にはオススメですが、もしKMZでやりたい人はZIP解凍の手法も合わせてコードに取り込むと良いでしょう。
事前準備
公開設定
Google Apps Scriptで取得するにはマイマップは公開状態にしておく必要があります。地図の共有ボタンをクリックして、「このリンクを知っている人なら誰でも表示できる」という状態にしておきましょう。
図:共有設定を公開にしておく
直リンクを取得する
直リンクを取得するのが大きな問題点。以下の手順で取得します。
- マイマップ項目のURLを全て取得する
- URLの中にあるmid=の文字列を取得する
- 「https://www.google.com/maps/d/u/0/kml?hl=ja&mid=」に2.の値をつなげる(cid以下は不要)
1https://www.google.com/maps/d/u/0/kml?hl=ja&mid=16ZW5vgAioNbrx0Xo-GApv1pOFNHEZrq_ - 3.のURLに&forcekml=1を付け加える。これでKML形式で出力になります。完成形は以下の通り
1https://www.google.com/maps/d/u/0/kml?hl=ja&mid=16ZW5vgAioNbrx0Xo-GApv1pOFNHEZrq_&forcekml=1
これでKMLへの直リンクを取得が出来ました。
図:KMLからURLを取得することも出来る
ソースコード
KMLをパースするコード
KMLはXMLそのものなのですが、XMLServiceでパースが出来るものの扱いにくいので、以前XMLをJSONに変換するコードを記述しましたがこれを使ってJSONに変換してあげてからだとGASでは操作しやすいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
//XMLをJSONに変換するとき利用する関数 function xmlToJson(xml) { //XMLをパースして変換関数に引き渡し結果を取得する var doc = XmlService.parse(xml); var result = {}; var root = doc.getRootElement(); result[root.getName()] = elementToJson(root); return result; } //XMLをJSONに変換する function elementToJson(element) { //結果を格納する箱を用意 var result = {}; // Attributesを取得する element.getAttributes().forEach(function(attribute) { result[attribute.getName()] = attribute.getValue(); }); //Child Elementを取得する element.getChildren().forEach(function(child) { //キーを取得する var key = child.getName(); //再帰的にもう一度この関数を実行して判定 var value = elementToJson(child); //XMLをJSONに変換する if (result[key]) { if (!(result[key] instanceof Array)) { result[key] = [result[key]]; } result[key].push(value); } else { result[key] = value; } }); //タグ内のテキストデータを取得する if (element.getText()) { result['Text'] = element.getText(); } return result; } |
データを出力するコード
JSON変換したデータを元にスプレッドシートに出力します。今回はStyle部分は特に触っていませんが、アイコンだったり色だったりとCSS的な役目を担っている部分なので、必要であればこれも取得して出力しておくと良いでしょう。
前述の事前準備で取得しておいたKMLへの直リンクのURLを記述しておきましょう。JSONファイルを出力するフォルダのIDも指定しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
//マイマップKMLのURL var url = "マイマップのKMLへの直リンクURLを入力" var folder = "出力先フォルダのIDを入力"; //マイマップを取得する function getMyMapdata() { //uiを取得 let ui = SpreadsheetApp.getUi(); //マイマップKMLを取得する var response = UrlFetchApp.fetch(url,{ muteHttpExceptions: true } ); //レスポンスコードで判定 if(response.getResponseCode() == 200){ //JSONデータに変換する var jsondoc = xmlToJson(response); //結果を出力する var json = JSON.stringify(jsondoc,null,"\t"); //JSONファイルを保存する var dateman = Utilities.formatDate(new Date(), "JST", "yyyy_MMdd_HHmm"); DriveApp.getFolderById(folder).createFile(dateman + ".json",json, MimeType.PLAIN_TEXT); //Folderを取り出す var element = jsondoc.kml["Document"].Folder; //書き込み用配列 var array = []; //elementを分解して取得 for(var i = 0;i<element.length;i++){ //レコードを一個取り出す let rec = element[i]; //親フォルダ名を取得する let parentname = rec.name.Text //placemarkエレメントを取得する let places = rec.Placemark; //placemarkの中身を取り出して配列を作る let temparr = []; for(var j = 0;j<places.length;j++){ //レコードを一個取り出す let place = places[j]; //緯度経度データをキレイにする let point; try{ point = String(place.Point.coordinates.Text); point = point.replace("\n",""); point = point.replace(/\s+/g, ""); }catch(e){ //undefinedなのでスルーする continue; } //画像データを取得する let extendimg = ""; try{ extendimg = place.ExtendedData.Data.value.Text; }catch(e){ //画像データが無いのでスルーする } //説明文を取得する let description = ""; try{ description = place.description.Text; }catch(e){ //画像データが無いのでスルーする } //temparrを構築 temparr = [ parentname, place.name.Text, place.styleUrl.Text, description, extendimg, point ] //配列に追加 array.push(temparr); } } //シートデータをクリアする let ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("placemark"); let sheet = ss.getRange("A2:F"); sheet.clearContent(); //スプレッドシートに書き出しする let lastColumn = array[0].length; //カラムの数を取得する let lastRow = array.length; //行の数を取得する ss.getRange(2,1,lastRow,lastColumn).setValues(array); //終了メッセージ ui.alert("データの書き出しを完了しました。") }else{ //取得エラー } } |
- ファイル名は日付とKMLの拡張子をつけて保存するようにします。
- XML2JSONでFolder項目以下にデータが集められてるのでelement変数に取得しておきます。
- 値が存在しない場合に備えてdescriptionやextendeddataについてはエラートラップを掛けておきます。
- pointは緯度経度データですが改行コードやスペースなどが混じってるのでこれらを除去するようにしています。
- Folder項目は配列で、各レコードにフォルダ名とPlacemarkの塊が入ってるのでそれぞれ取り出し、書き込み用配列を作ります
- 最期に一括で書き出しを行います。
- KMLのまま出力する場合は、var blob = response.getBlob().setName(dateman + ".kmz");で保存が可能です。
図:キレイに取得できました。