Google Apps Scriptでマイマップデータを取得する【GAS】

以前、Google Apps ScriptでスプレッドシートデータをGoogle Earthからのリクエストに応じてネットワークリンクを生成しデータを返す仕組みを作りました。一方、GoogleマイマップはKMLを出力出来るのですが、マイマップデータのバックアップを取りたいと思っても、KML出力しか無い為、データで管理したい場合、ちょっと困ります。

ということで、今回は逆パターンのマイマップのデータをスプレッドシートに書き出して管理する手法をまとめました。

Google Apps Scriptでマップ作成とKML生成【GAS】

今回利用するスプレッドシート

今回は昔作ったマイマップデータを取得してスプレッドシートに出力します。KMZ形式で取得した場合は、一旦解凍して中に入ってるdoc.kmlを取得する必要があるため、今回は手軽なKML形式の方で取得します。

KMZ形式の場合独自アイコン等も取得出来るので個人的にはオススメですが、もしKMZでやりたい人はZIP解凍の手法も合わせてコードに取り込むと良いでしょう。

Google Apps ScriptでZIP圧縮・解凍をやってみる【GAS】

事前準備

公開設定

Google Apps Scriptで取得するにはマイマップは公開状態にしておく必要があります。地図の共有ボタンをクリックして、「このリンクを知っている人なら誰でも表示できる」という状態にしておきましょう。

図:共有設定を公開にしておく

直リンクを取得する

直リンクを取得するのが大きな問題点。以下の手順で取得します。

  1. マイマップ項目のURLを全て取得する
  2. URLの中にあるmid=の文字列を取得する
  3. https://www.google.com/maps/d/u/0/kml?hl=ja&mid=」に2.の値をつなげる(cid以下は不要)
    https://www.google.com/maps/d/u/0/kml?hl=ja&mid=16ZW5vgAioNbrx0Xo-GApv1pOFNHEZrq_
  4. 3.のURLに&forcekml=1を付け加える。これでKML形式で出力になります。完成形は以下の通り
    https://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では操作しやすいです。

//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;
}

Google Apps ScriptでXMLをよしなに扱う方法【GAS】

データを出力するコード

JSON変換したデータを元にスプレッドシートに出力します。今回はStyle部分は特に触っていませんが、アイコンだったり色だったりとCSS的な役目を担っている部分なので、必要であればこれも取得して出力しておくと良いでしょう。

前述の事前準備で取得しておいたKMLへの直リンクのURLを記述しておきましょう。JSONファイルを出力するフォルダのIDも指定しておきます。

//マイマップ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");で保存が可能です。

図:キレイに取得できました。

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)