【GAS】スプレッドシートからスライド作成

GAS

こんにちは!ウメハラ(plumfield56)です。

この記事ではスプレッドシートからスライド作成を汎用的に行う方法を解説しています。
下記の動画のようにスプレッドシートのフォーマットの数分、必要なページを複製しテキストを置換させていきます。

前提としてコードはスプレッドシートのコンテナバインドスクリプト上で記載していきたいと思います。

全体の手順

この記事では下記の手順で行っていきたいと思います。

  1. スプレッドシート情報をオブジェクト化する
  2. 必要な分のスライドの複製/削除を行う
  3. 2で作成したスライドオブジェクトをリストとして保持
  4. 3のスライドのオブジェクトを全て取得し、文字列を置換

必要な分のスライドを複製/削除後に再び、全ページを取得するという方法もありますが、それだとどのページがいくつ複製されたのか把握しづらかったのでその方法でのコードを作るのはやめました。

スプレッドシートをオブジェクトへ変換する

スプレッドシートは下記を用意します。

このスプレッドシートから下記の様なリストを作成していきたいと思います。
行ごとにリストの1要素となっていて、各要素は1行目に入っている項目名をkey、セルに入っている内容をvalueにしたオブジェクトになっています。

[ { 'フォーマット': 'フォーマット1', '名前': 'AAA', '年齢': 23, '好きなもの': 'aaa' },
  { 'フォーマット': 'フォーマット1', '名前': 'BBB', '年齢': 24, '好きなもの': 'bbb' },
  { 'フォーマット': 'フォーマット2', '名前': 'CCC', '年齢': 25, '好きなもの': 'ccc' },
  { 'フォーマット': 'フォーマット3', '名前': 'DDD', '年齢': 26, '好きなもの': 'ddd' },
  { 'フォーマット': 'フォーマット3', '名前': 'EEE', '年齢': 27, '好きなもの': 'eee' },
  { 'フォーマット': 'フォーマット3', '名前': 'FFF', '年齢': 28, '好きなもの': 'fff' },
  { 'フォーマット': 'フォーマット3', '名前': 'GGG', '年齢': 29, '好きなもの': 'ggg' } ]

上記のリストを作成するコードが下記になります。

function myFunction() {

  const sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  const values = sht.getDataRange().getValues();
  const header = values.splice(0, 1).flat();

  const ssObj = [];
  for(const row of values) {
    const obj = {};
    row.forEach((val, i) => obj[header[i]] = val);
    ssObj.push(obj);
  }
  console.log(ssObj);
}

スライドの複製 / 削除

スライドの複製/削除はduplicate/removeメソッドを使うことで可能です。
スライドの複製は指定したスライドの次のページとして複製されます。

スライドの作成

slideオブジェクト.duplicate();

スライドの削除

slideオブジェクト.remove();

上記でスプレッドシート情報をオブジェクトでまとめる際にフォーマットの数分、スライドを複製します。

function myFunction() {

  const slideId = 'id';
  const slides = SlidesApp.openById(slideId).getSlides();

  // スライド情報をまとめるオブジェクトを作成 ・・・ 注1
  const slidesObj = {
    'フォーマット1': {slide: slides[1], slides: [slides[1]], index: 0},
    'フォーマット2': {slide: slides[2], slides: [slides[2]], index: 0},
    'フォーマット3': {slide: slides[3], slides: [slides[3]], index: 0},
  }

  //スプレッドシート
  const sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  const values = sht.getDataRange().getValues();
  const header = values.splice(0, 1).flat();

  const ssObj = [];
  for(const row of values) {
    const obj = {};
    row.forEach((val, i) => {
      obj[header[i]] = val;
      
      // 項目名がフォーマットでobjにcreatedが存在したらduplicate()で複製
      if(header[i] === 'フォーマット') {
        if(slidesObj[val]['created']) {
          const duplicateSlide = slidesObj[val]['slide'].duplicate();
          // 2回目以降で複製するスライドを変更するために再代入 ・・・ 注3
          slidesObj[val]['slide'] = duplicateSlide;
          // 複製したslidesのkeyに追加 ・・・ 注4
          slidesObj[val]['slides'].push(duplicateSlide);
        }
        // 複製したslidesのkeyに追加 ・・・ 注2
        slidesObj[val]['created'] = true;
      }
    });
    ssObj.push(obj);
  }

  // 存在しないフォーマットの削除
  for(const [key, val] of Object.entries(slidesObj)) {
    slidesObj[key]['created'] ?  true: slidesObj[key]['slide'].remove();
  }

  console.log(slidesObj);
  /*
  { 'フォーマット1': { slide: {}, slides: [ {}, {} ], index: 0, created: true },
    'フォーマット2': { slide: {}, slides: [ {} ], index: 0, created: true },
    'フォーマット3': { slide: {}, slides: [ {}, {}, {}, {} ], index: 0, created: true } }
  */
}

これでslidesObjのslidesの中に必要な分のスライドが用意されました。
各フォーマットをコピーするのは2回目以降で必要なスライド数が1枚であれば、フォーマットとして用意しているスライドを使用します。
そのため、注2にあるように1回目に複製されず2回目以降のみ複製されるようにcreatedというkeyを作成しています。

文字列の置換

function myFunction() {

  const slideId = 'id';
  const slides = SlidesApp.openById(slideId).getSlides();

  const slidesObj = {
    'フォーマット1': {slide: slides[1], slides: [slides[1]], index: 0},
    'フォーマット2': {slide: slides[2], slides: [slides[2]], index: 0},
    'フォーマット3': {slide: slides[3], slides: [slides[3]], index: 0},
  }

  //スプレッドシート操作
  const sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  const values = sht.getDataRange().getValues();
  const header = values.splice(0, 1).flat();

  const ssObj = [];

  //スプレッドシートのオブジェクト作成とスライド複製
  for(const row of values) {
    const obj = {};
    row.forEach((val, i) => {
      obj[header[i]] = val;
      
      if(header[i] === 'フォーマット') {
        if(slidesObj[val]['created']) {
          const duplicateSlide = slidesObj[val]['slide'].duplicate();
          slidesObj[val]['slide'] = duplicateSlide;
          slidesObj[val]['slides'].push(duplicateSlide);
        }
        slidesObj[val]['created'] = true;
      }
    });
    ssObj.push(obj);
  }

  // 存在しないフォーマットの削除
  for(const [key, val] of Object.entries(slidesObj)) {
    slidesObj[key]['created'] ?  true: slidesObj[key]['slide'].remove();
  }
  console.log(slidesObj);

  // 文字の置換
  for(const obj of ssObj) {
    const format = obj['フォーマット'];
 // 使用するフォーマットの指定

    const num = slidesObj[format]['index'];
 // slidesのいくつ目の要素に入っているスライドを操作するか指定
    const slide = slidesObj[format]['slides'][num];
    const elems = slide.getPageElements();

    for(const elem of elems) {
      if(elem.getPageElementType().toString() === 'SHAPE') {
        const textRange = elem.asShape().getText();
        const text = textRange.asString().replace('\n', '');
 // 仕様なのか改行が入っている状態となっているので注意

        if(obj[text]) {
          textRange.replaceAllText(text, obj[text]);
        }
      }
    }

    slidesObj[format]['index'] ++;
  }
}

Shapeオブジェクトからテキストを取得すると文字列の最後に改行が入っている状態になっているので注意ください。

コメント

タイトルとURLをコピーしました