أساسيات برمجة التطبيقات مع جداول بيانات Google #4: تنسيق البيانات

1. مقدمة

مرحبًا بك في الجزء الرابع من أساسيات برمجة التطبيقات مع قائمة تشغيل الدروس التطبيقية حول الترميز في "جداول بيانات Google".

من خلال إكمال هذا الدرس التطبيقي، يمكنك تعلّم كيفية تنسيق بيانات جدول البيانات في "برمجة تطبيقات Google" وكتابة وظائف لإنشاء جداول بيانات منظّمة مليئة بالبيانات المنسّقة التي يتم جلبها من واجهة برمجة تطبيقات عامة.

ما ستتعرَّف عليه

  • كيفية تطبيق عمليات تنسيق مختلفة في "جداول بيانات Google" في "برمجة تطبيقات Google".
  • كيفية تحويل قائمة بكائنات JSON وسماتها إلى ورقة بيانات منظمة باستخدام برمجة التطبيقات.

قبل البدء

هذا هو الدرس التطبيقي الرابع حول الترميز الأساسي لبرمجة التطبيقات مع "جداول بيانات Google". قبل بدء هذا الدرس التطبيقي حول الترميز، تأكَّد من إكمال الدروس التطبيقية السابقة حول الترميز:

  1. وحدات الماكرو والدوال المخصصة
  2. جداول البيانات وجداول البيانات والنطاقات
  3. استخدام البيانات

الأشياء التي تحتاج إليها

  • فهم المواضيع الأساسية لبرمجة التطبيقات التي تم استكشافها في الدروس التطبيقية حول الترميز السابقة لقائمة التشغيل هذه.
  • دراية أساسية بمحرِّر "برمجة تطبيقات Google"
  • إلمام أساسي بـ جداول بيانات Google
  • إمكانية قراءة تدوين A1 في "جداول بيانات Google"
  • الإلمام بأساسيات JavaScript وفئة String

2. إعداد

قبل المتابعة، تحتاج إلى جدول بيانات يحتوي على بعض البيانات. كما ذكرنا سابقًا، قدّمنا ورقة بيانات يمكنك نسخها لهذه التمارين. اتّبِع الخطوات التالية:

  1. انقر على هذا الرابط لنسخ ورقة البيانات، ثم انقر على إنشاء نسخة. يتم وضع جدول البيانات الجديد في مجلد Google Drive ويكون باسم "نسخة من تنسيق البيانات"
  2. انقر على عنوان جدول البيانات وغيّره من &quot؛نسخة من تنسيق البيانات&quot؛ إلى "تنسيق البيانات&; يجب أن تبدو جدول البيانات كما يلي، مع بعض المعلومات الأساسية عن أفلام الحروب الثلاثة الأولى:

c4f49788ed82502b.png

  1. اختَر الإضافات&gt؛ أو برمجة تطبيقات Google لفتح محرِّر النصوص البرمجية.
  2. انقر على عنوان مشروع "برمجة التطبيقات" وغيِّره من "المشروعات&&؛ بدون عنوان" إلى "&&;تنسيق البيانات" انقر على إعادة تسمية لحفظ تغيير العنوان.

باستخدام جدول البيانات هذا والمشروع، ستكون مستعدًا لبدء الدرس التطبيقي حول الترميز. انتقِل إلى القسم التالي لبدء التعرّف على التنسيق الأساسي في "برمجة تطبيقات Google".

3- إنشاء قائمة مخصّصة

يمكنك تطبيق العديد من طرق التنسيق الأساسية في "برمجة تطبيقات Google" على "جداول بيانات Google". توضّح التمارين التالية بعض طرق تنسيق البيانات. للمساعدة في التحكم في إجراءات التنسيق، لننشئ قائمة مخصّصة تتضمن العناصر التي ستحتاج إليها. تم توضيح عملية إنشاء القوائم المخصّصة في الدرس التطبيقي حول الترميز العمل باستخدام البيانات، ولكننا سنلخصها هنا مرة أخرى.

التنفيذ

لنبدأ قائمة مخصصة.

  1. في محرِّر "برمجة تطبيقات Google"، استبدل الرمز في مشروع النص البرمجي بما يلي:
/**
 * A special function that runs when the spreadsheet is opened
 * or reloaded, used to add a custom menu to the spreadsheet.
 */
function onOpen() {
  // Get the spreadsheet's user-interface object.
  var ui = SpreadsheetApp.getUi();

  // Create and add a named menu and its items to the menu bar.
  ui.createMenu('Quick formats')
   .addItem('Format row header', 'formatRowHeader')
   .addItem('Format column header', 'formatColumnHeader')
   .addItem('Format dataset', 'formatDataset') 
  .addToUi();
}
  1. احفظ مشروع النص البرمجي.
  2. في محرِّر النص البرمجي، اختَر onOpen من قائمة الدوال وانقر على تشغيل. يؤدي هذا إلى تشغيل onOpen() لإعادة إنشاء قائمة جداول البيانات، وبالتالي لا تحتاج إلى إعادة تحميل جدول البيانات.

مراجعة الرموز

لنراجع هذا الرمز لفهم آلية عمله. في onOpen()، يستخدم السطر الأول طريقة getUi() لاكتساب عنصر Ui الذي يمثل واجهة المستخدم لجدول البيانات النشط الذي يرتبط به هذا النص البرمجي.

تنشئ الأسطر التالية قائمة (Quick formats)، وأضِف عناصر القائمة (Format row header وFormat column header وFormat dataset) إلى القائمة، ثم أضِف القائمة إلى واجهة جدول البيانات. ويتم هذا باستخدام الطرق createMenu(caption) وaddItem(caption, functionName) وaddToUi() على التوالي.

تنشئ الطريقة addItem(caption, functionName) اتصالاً بين تصنيف عنصر القائمة ودالة "برمجة التطبيقات" التي يتم تشغيلها عند اختيار عنصر القائمة. على سبيل المثال، يؤدي اختيار عنصر القائمة Format row header إلى محاولة "جداول بيانات Google" تشغيل الدالة formatRowHeader() (وهي غير متوفّرة بعد).

النتائج

في جدول البيانات، انقر على قائمة Quick formats لعرض عناصر القائمة الجديدة:

1d639a41f3104864.png

يؤدي النقر على هذه العناصر إلى حدوث خطأ نظرًا لأنك لم تنفّذ الوظائف المقابلة لها، لذلك دعنا نفعل ذلك بعد ذلك.

4. تنسيق صف عنوان

تحتوي مجموعات البيانات في جداول البيانات غالبًا على صفوف عناوين لتحديد البيانات في كل عمود. من الأفضل تنسيق صفوف العناوين لفصلها بصريًا عن بقية البيانات في جدول البيانات.

في الدرس التطبيقي الأول، أنشأت وحدة ماكرو لرأسك وعدّلت رمزها. ستتمكّن هنا من تنسيق صف عنوان من البداية باستخدام "برمجة التطبيقات". سيصف صف العنوان الذي ستنشئه غامقًا نص العنوان ويلوّن الخلفية باللون الأخضر الداكن، ويلون النص باللون الأبيض، ويضيف حدودًا صلبة.

التنفيذ

لتنفيذ عملية التنسيق، ستستخدم أساليب خدمة جداول البيانات نفسها التي استخدمتها من قبل، ولكنك ستستخدم الآن أيضًا بعض أساليب التنسيق في الخدمة. اتّبِع الخطوات التالية:

  1. في محرِّر "برمجة تطبيقات Google"، أضِف الدالة التالية إلى نهاية مشروع النص البرمجي:
/**
 * Formats top row of sheet using our header row style.
 */
function formatRowHeader() {
  // Get the current active sheet and the top row's range.
  var sheet = SpreadsheetApp.getActiveSheet();
  var headerRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
 
  // Apply each format to the top row: bold white text,
  // blue-green background, and a solid black border
  // around the cells.
  headerRange
    .setFontWeight('bold')
    .setFontColor('#ffffff')
    .setBackground('#007272')
    .setBorder(
      true, true, true, true, null, null,
      null,
      SpreadsheetApp.BorderStyle.SOLID_MEDIUM);

}
  1. احفظ مشروع النص البرمجي.

مراجعة الرموز

مثل العديد من مهام التنسيق، يكون رمز برمجة التطبيقات واضحًا للغاية. يستخدم السطران الأولان الطرق التي رأيتها من قبل للحصول على مرجع إلى الورقة النشطة الحالية (sheet) وصف الصف الأعلى من الورقة (headerRange)). تحدد طريقة Sheet.getRange(row, column, numRows, numColumns) الصف العلوي، بما في ذلك الأعمدة التي تحتوي على بيانات فقط. تعرض طريقة Sheet.getLastColumn() فهرس العمود للعمود الأخير الذي يحتوي على بيانات في الورقة. في المثال الحالي، يظهر العمود E( #39;s) (url).

يستقبل باقي الرمز ببساطة العديد من طرق Range لتطبيق خيارات التنسيق على جميع الخلايا في headerRange. للحفاظ على سهولة قراءة الرمز، نستخدم سلسلة الطرق لاستدعاء كل طريقة تنسيق واحدة تلو الأخرى:

تحتوي الطريقة الأخيرة على العديد من المعلمات، لذلك لنراجع ما يقوم به كل منها. تخبر المعلمات الأربع الأولى هنا (التي تم ضبطها جميعًا على true) "برمجة التطبيقات" بأنّ الحد يجب إضافته أعلى وأسفل ويمين النطاق ويمينه. توجِّه المعلّمتان الخامسة والسادسة (null وnull) "برمجة تطبيقات Google" لتجنُّب تغيير أي حدود للحدود ضمن النطاق المحدّد. تشير المعلمة السابعة (null) إلى لون الحد التلقائي في اللون الأسود. وأخيرًا، تحدّد المعلّمة الأخيرة نوع نمط الحدود المطلوب استخدامه، استنادًا إلى الخيارات المتوفّرة في SpreadsheetApp.BorderStyle.

النتائج

يمكنك الاطّلاع على وظيفة التنسيق أثناء تنفيذها عن طريق ما يلي:

  1. احفظ مشروع النص البرمجي في محرِّر "برمجة تطبيقات Google"، إذا لم يسبق لك إجراء ذلك.
  2. انقر على عنصر القائمة التنسيقات السريعة > تنسيق صف الصف.

من المفترض أن تظهر النتائج على النحو التالي:

a1a63770c2c3becc.gif

لقد أكملت الآن مهمة تنسيق تلقائيًا. يُطبّق القسم التالي الأسلوب نفسه لإنشاء نمط تنسيق مختلف لرؤوس الأعمدة.

5. تنسيق عنوان عمود

إذا كان بإمكانك إنشاء عنوان صف مخصّص، يمكنك إنشاء عنوان عمود أيضًا. تؤدي رؤوس الأعمدة إلى زيادة سهولة القراءة لمجموعات بيانات معيّنة. على سبيل المثال، يمكن تحسين عمود العناوين في جدول البيانات هذا باستخدام خيارات التنسيق التالية:

  • تغميق النص
  • طبِّق الخط المائل على النص.
  • إضافة حدود الخلية
  • إدراج روابط تشعّبية، باستخدام محتوى العمود url بعد إضافة الروابط التشعّبية هذه، يمكنك إزالة عمود url للمساعدة في تنظيم الورقة.

بعد ذلك، ستنفِّذ دالة formatColumnHeader() لتطبيق هذه التغييرات على العمود الأول في الورقة. للمساعدة في تسهيل قراءة الرمز، عليك أيضًا تنفيذ وظيفتَين مساعدتَين.

التنفيذ

وكما في السابق، عليك إضافة دالة لبرمجة تنسيق رأس العمود. اتّبِع الخطوات التالية:

  1. في محرِّر"برمجة تطبيقات Google"، أضِف الدالة formatColumnHeader() التالية إلى نهاية مشروع النص البرمجي:
/**
 * Formats the column header of the active sheet.
 */ 
function formatColumnHeader() {  
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // Get total number of rows in data range, not including
  // the header row.
  var numRows = sheet.getDataRange().getLastRow() - 1;
  
  // Get the range of the column header.
  var columnHeaderRange = sheet.getRange(2, 1, numRows, 1);
  
  // Apply text formatting and add borders.
  columnHeaderRange
    .setFontWeight('bold')
    .setFontStyle('italic')
    .setBorder(
      true, true, true, true, null, null,
      null,
      SpreadsheetApp.BorderStyle.SOLID_MEDIUM);
 
  // Call helper method to hyperlink the first column contents
  // to the url column contents.
  hyperlinkColumnHeaders_(columnHeaderRange, numRows); 
}
  1. أضِف دالات المساعدة التالية إلى نهاية مشروع النص البرمجي، بعد دالة formatColumnHeader():
/**
 * Helper function that hyperlinks the column header with the
 * 'url' column contents. The function then removes the column.
 *
 * @param {object} headerRange The range of the column header
 *   to update.
 * @param {number} numRows The size of the column header.
 */
function hyperlinkColumnHeaders_(headerRange, numRows) {
  // Get header and url column indices.
  var headerColIndex = 1; 
  var urlColIndex = columnIndexOf_('url');  
  
  // Exit if the url column is missing.
  if(urlColIndex == -1)
    return; 
  
  // Get header and url cell values.
  var urlRange =
    headerRange.offset(0, urlColIndex - headerColIndex);
  var headerValues = headerRange.getValues();
  var urlValues = urlRange.getValues();
  
  // Updates header values to the hyperlinked header values.
  for(var row = 0; row < numRows; row++){
    headerValues[row][0] = '=HYPERLINK("' + urlValues[row]
      + '","' + headerValues[row] + '")';
  }
  headerRange.setValues(headerValues);
  
  // Delete the url column to clean up the sheet.
  SpreadsheetApp.getActiveSheet().deleteColumn(urlColIndex);
}

/**
 * Helper function that goes through the headers of all columns
 * and returns the index of the column with the specified name
 * in row 1. If a column with that name does not exist,
 * this function returns -1. If multiple columns have the same
 * name in row 1, the index of the first one discovered is
 * returned.
 * 
 * @param {string} colName The name to find in the column
 *   headers. 
 * @return The index of that column in the active sheet,
 *   or -1 if the name isn't found.
 */ 
function columnIndexOf_(colName) {
  // Get the current column names.
  var sheet = SpreadsheetApp.getActiveSheet();
  var columnHeaders =
    sheet.getRange(1, 1, 1, sheet.getLastColumn());
  var columnNames = columnHeaders.getValues();
  
  // Loops through every column and returns the column index
  // if the row 1 value of that column matches colName.
  for(var col = 1; col <= columnNames[0].length; col++)
  {
    if(columnNames[0][col-1] === colName)
      return col; 
  }

  // Returns -1 if a column named colName does not exist. 
  return -1; 
}
  1. احفظ مشروع النص البرمجي.

مراجعة الرموز

لنراجع الرمز في كل واحدة من هذه الوظائف الثلاث بشكل منفصل:

formatColumnHeader()

كما توقعت على الأرجح، بدأت الأسطر القليلة الأولى من هذه الدالة بإعداد المتغيّرات التي تشير إلى الورقة والنطاق الذي يهمّنا:

  • يتم تخزين الورقة النشطة في sheet.
  • يتم حساب عدد الصفوف في عنوان العمود وحفظه في numRows. يطرح الرمز هنا واحدة حتى لا يتضمن عدد الصفوف عنوان العمود: title.
  • يتم تخزين النطاق الذي يغطي عنوان العمود في columnHeaderRange.

يطبّق الرمز بعد ذلك الحدود ويعمل على تنسيق نطاق عنوان العمود، كما هو الحال في formatRowHeader(). يتم هنا استخدام Range.setFontStyle(fontStyle) لجعل النص مائلاً.

إضافة الروابط التشعّبية إلى عمود العنوان أكثر تعقيدًا، لذلك يستدعي formatColumnHeader() hyperlinkColumnHeaders_(headerRange, numRows) لتنفيذ المهمة. ويساعد هذا في إبقاء الرمز منظمًا وسهل القراءة.

hyperlinkColumnHeaders_(headerRange, numRows)

تحدّد هذه الدالة المساعدة أولاً فهارس الأعمدة (يُفترض أنها الفهرس 1) وعمود url. وتطلب الدالة columnIndexOf_('url') للحصول على فهرس عمود عنوان URL. في حال عدم العثور على عمود url، سيتم الخروج من الطريقة بدون تعديل أي بيانات.

تحصل الدالة على نطاق جديد (urlRange) يغطي عناوين URL المقابلة لصفوف أعمدة العناوين. ويتم ذلك باستخدام طريقة Range.offset(rowOffset, columnOffset) التي تضمن أن يكون النطاقان بالحجم نفسه. ويتم بعد ذلك استرجاع القيم في كل من العمود headerColumn والعمود url (headerValues وurlValues).

ومن ثمّ تكرّر الدالة كل قيمة خلية لرأس العمود وتستبدلها بصيغة =HYPERLINK() لجداول البيانات التي يتم إنشاؤها باستخدام العنوان وurl محتوى العمود. ويتم بعد ذلك إدراج قيم العنوان المعدَّلة في الورقة باستخدام Range.setValues(values).

وأخيرًا، للمساعدة في الحفاظ على أمان الورقة وإزالة المعلومات المكرّرة، يتم استدعاء Sheet.deleteColumn(columnPosition) لإزالة العمود url.

columnIndexOf_(colName)

هذه الوظيفة المساعدة هي وظيفة أداة بسيطة تبحث في الصف الأول من الورقة لاسم محدّد. تستخدم الأسطر الثلاثة الأولى طرقًا رأيتها للحصول على قائمة بأسماء رؤوس الأعمدة من الصف الأول في جدول البيانات. ويتم تخزين هذه الأسماء في أسماء الأعمدة المتغيرة.

بعد ذلك، تراجع الدالة كل اسم بالترتيب. وإذا تم العثور على اسم يتطابق مع الاسم الذي يتم البحث عنه، يتوقف ويعرض فهرس العمود. إذا وصلت إلى نهاية قائمة الأسماء بدون العثور على الاسم، سيتم عرض -1 للإشارة إلى أنه لم يتم العثور على الاسم.

النتائج

يمكنك الاطّلاع على وظيفة التنسيق أثناء تنفيذها عن طريق ما يلي:

  1. احفظ مشروع النص البرمجي في محرِّر "برمجة تطبيقات Google"، إذا لم يسبق لك إجراء ذلك.
  2. انقر على عنصر القائمة التنسيقات السريعة > تنسيق عمود العمود.

من المفترض أن تظهر النتائج على النحو التالي:

7497cf1b982aeff6.gif

لقد أتممت الآن مهمة تنسيق أخرى تلقائيًا. يعرض العمود التالي صفَي العمود والعمود ويحدّد كيفية تنسيق البيانات.

6- تنسيق مجموعة البيانات

الآن وبعد أن أنشأت عناوين، هيّا تنشئ وظيفة تعمل على تنسيق بقية البيانات في جدول البيانات. سنستخدم خيارات التنسيق التالية:

  • ألوان خلفية صف بديل (تُعرف باسم التباين)
  • تغيير تنسيقات التاريخ
  • تطبيق الحدود
  • تغيير حجم كل الأعمدة والصفوف تلقائيًا

سيكون عليك الآن إنشاء دالة formatDataset() وطريقة مساعد إضافية لتطبيق هذه التنسيقات على بيانات الورقة.

التنفيذ

كما في السابق، أضِف دالة لبرمجة تنسيق البيانات. اتّبِع الخطوات التالية:

  1. في محرِّر "برمجة تطبيقات Google"، أضِف الدالة formatDataset() التالية إلى نهاية مشروع النص البرمجي:
/**
 * Formats the sheet data, excluding the header row and column.
 * Applies the border and banding, formats the 'release_date'
 * column, and autosizes the columns and rows.
 */
function formatDataset() {
  // Get the active sheet and data range.
  var sheet = SpreadsheetApp.getActiveSheet(); 
  var fullDataRange = sheet.getDataRange();

  // Apply row banding to the data, excluding the header
  // row and column. Only apply the banding if the range
  // doesn't already have banding set.
  var noHeadersRange = fullDataRange.offset(
    1, 1,
    fullDataRange.getNumRows() - 1,
    fullDataRange.getNumColumns() - 1);

  if (! noHeadersRange.getBandings()[0]) {
    // The range doesn't already have banding, so it's
    // safe to apply it.
    noHeadersRange.applyRowBanding(
      SpreadsheetApp.BandingTheme.LIGHT_GREY,
      false, false);
  }

  // Call a helper function to apply date formatting
  // to the column labeled 'release_date'.
  formatDates_( columnIndexOf_('release_date') );
  
  // Set a border around all the data, and resize the
  // columns and rows to fit.
  fullDataRange.setBorder(
    true, true, true, true, null, null,
    null,
    SpreadsheetApp.BorderStyle.SOLID_MEDIUM);

  sheet.autoResizeColumns(1, fullDataRange.getNumColumns());
  sheet.autoResizeRows(1, fullDataRange.getNumRows());
}
  1. أضِف الدالة المساعدة التالية في نهاية مشروع النص البرمجي، بعد دالة formatDataset():
/** 
 * Helper method that applies a
 * "Month Day, Year (Day of Week)" date format to the
 * indicated column in the active sheet. 
 *
 * @param {number} colIndex The index of the column
 *   to format.
 */ 
function formatDates_(colIndex) {
  // Exit if the given column index is -1, indicating
  // the column to format isn't present in the sheet.
  if (colIndex < 0)
    return; 

  // Set the date format for the date column, excluding
  // the header row.
  var sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange(2, colIndex, sheet.getLastRow() - 1, 1)
    .setNumberFormat("mmmm dd, yyyy (dddd)");
}
  1. احفظ مشروع النص البرمجي.

مراجعة الرموز

لنراجع الرمز في كلٍ من هاتين الوسيلتين بشكلٍ منفصل:

formatDataset()

تتبع هذه الدالة نمطًا مشابهًا لدوال التنسيق السابقة التي تنفيذها من قبل. أولاً، تحصل على متغيرات الاحتفاظ بإشارات للورقة النشطة (ورقة) ونطاق البيانات (fullDataRange).

ثانيًا، يستخدم أسلوب Range.offset(rowOffset, columnOffset, numRows, numColumns) لإنشاء نطاق (noHeadersRange) يغطي جميع البيانات في الورقة، باستثناء رؤوس الأعمدة والصفوف. يتحقق الرمز بعد ذلك مما إذا كان هذا النطاق الجديد يتضمّن نطاقًا حاليًا (باستخدام Range.getBandings())، وذلك ضروري لأنّ برمجة التطبيقات تعرض رسالة خطأ إذا حاولت تطبيق ربط جديد في حال توفّر هذا النطاق. إذا لم يتوفّر تباين، ستضيف الدالة نطاقًا رماديًا فاتحًا باستخدام Range.applyRowBanding(bandingTheme, showHeader, showFooter). وبخلاف ذلك، تنتقل الوظيفة إلى الأمام.

تستدعي الخطوة التالية دالة المساعد formatDates_(colIndex) لتنسيق التواريخ في العمود المسمى "release_date' (كما هو موضّح أدناه). يتم تحديد العمود باستخدام وظيفة المساعد columnIndexOf_(colName) التي تم تنفيذها سابقًا.

وأخيرًا، يتم إنهاء التنسيق عن طريق إضافة حد آخر (كما في السابق)، وتغيير حجم كل عمود وصف في شكل تلقائي ليناسب البيانات التي تحتوي عليها باستخدام الطريقتين Sheet.autoResizeColumns(columnPosition) وSheet.autoResizeColumns(columnPosition).

formatDates_(colIndex)

تُطبّق هذه الدالة المساعدة تنسيق تاريخ محدّدًا على عمود باستخدام فهرس العمود المقدّم. وبشكل خاص، فإنها تنسِق قيم التاريخ على النحو التالي: يوم، شهر، سنة (يوم من الأسبوع)&;

أولاً، تتحقّق الدالة من أن فهرس العمود صالح (أي 0 أو أكبر). وإذا لم يكن الأمر كذلك، سيتم إرجاعها بدون اتخاذ أي إجراء. تمنع عملية التحقق هذه الأخطاء التي قد تحدث إذا كان، على سبيل المثال، لم تحتوي الورقة على عمود "release_date&#39؛

بعد التحقق من صحة فهرس الأعمدة، تحصل الدالة على النطاق الذي يغطي ذلك العمود (باستثناء صف العنوان)، وتستخدم Range.setNumberFormat(numberFormat) لتطبيق التنسيق.

النتائج

يمكنك الاطّلاع على وظيفة التنسيق أثناء تنفيذها عن طريق ما يلي:

  1. احفظ مشروع النص البرمجي في محرِّر "برمجة تطبيقات Google"، إذا لم يسبق لك إجراء ذلك.
  2. انقر على عنصر القائمة التنسيقات السريعة &gt؛ تنسيق مجموعة البيانات.

من المفترض أن تظهر النتائج على النحو التالي:

3cfedd78b3e25f3a.gif

لقد نجحت في تنفيذ مهمة تنسيق أخرى تلقائيًا. الآن وبعد توفّر أوامر التنسيق هذه هذه، لنضيف المزيد من البيانات لتطبيقها عليها.

7- استرجاع بيانات واجهة برمجة التطبيقات وتنسيقها

لقد رأيت حتى الآن في هذا الدرس التطبيقي كيفية استخدام "برمجة التطبيقات" كوسيلة بديلة لتنسيق جدول البيانات. بعد ذلك، ستكتب الرمز الذي يسحب البيانات من واجهة برمجة تطبيقات عامة، ويدرجها في جدول بياناتك وينسّقها حتى تكون قابلة للقراءة.

في الدرس التطبيقي الأخير حول الترميز، تعلّمت كيفية سحب البيانات من واجهة برمجة التطبيقات. ستستخدم الأساليب نفسها هنا. في هذا التمرين، سنستخدم Star Wars API (SWAPI) لتعبئة جدول البيانات. على وجه التحديد، ستستخدم واجهة برمجة التطبيقات للحصول على معلومات عن الشخصيات الرئيسية التي تظهر في الأفلام الثلاثة الأصلية من سلسلة Star Wars.

وسيؤدي الرمز إلى استدعاء واجهة برمجة التطبيقات للحصول على قدر كبير من بيانات JSON، وتحليل الاستجابة، ووضع البيانات في ورقة جديدة، ثم تنسيق الورقة.

التنفيذ

في هذا القسم، ستضيف بعض عناصر القائمة الإضافية. يستدعي كل عنصر في القائمة نصًا برمجيًا برنامجًا تضمينيًا يعمل على تمرير متغيرات خاصة بالعنصر إلى الدالة الرئيسية (createResourceSheet_()). وسيكون عليك تنفيذ هذه الدالة وثلاث دوال مساعد إضافية. كما في السابق، تساعد وظائف المساعد في عزل الأجزاء المقسّمة ذاتيًا عن المهمة وتساعد في الحفاظ على سهولة قراءة الرمز.

عليك اتخاذ الإجراءات التالية:

  1. في محرِّر"برمجة تطبيقات Google"، عدِّل الدالة onOpen() في مشروع النص البرمجي لمطابقة ما يلي:
/**
 * A special function that runs when the spreadsheet is opened
 * or reloaded, used to add a custom menu to the spreadsheet.
 */
function onOpen() {
  // Get the Ui object.
  var ui = SpreadsheetApp.getUi();

  // Create and add a named menu and its items to the menu bar.
  ui.createMenu('Quick formats')
    .addItem('Format row header', 'formatRowHeader')
    .addItem('Format column header', 'formatColumnHeader')
    .addItem('Format dataset', 'formatDataset')
    .addSeparator()
    .addSubMenu(ui.createMenu('Create character sheet')
                .addItem('Episode IV', 'createPeopleSheetIV')
                .addItem('Episode V', 'createPeopleSheetV')
                .addItem('Episode VI', 'createPeopleSheetVI')
                )
    .addToUi();
}
  1. احفظ مشروع النص البرمجي.
  2. في محرِّر النص البرمجي، اختَر onOpen من قائمة الدوال وانقر على تشغيل. يؤدي هذا إلى تشغيل onOpen() لإعادة إنشاء قائمة جداول البيانات باستخدام الخيارات الجديدة التي أضفتها.
  3. لإنشاء ملف "برمجة تطبيقات Google"، بجانب الملفات، انقر على رمز إضافة ملف إضافة ملف > Script.
  4. أدخِل اسمًا للنص البرمجي الجديد لواجهة برمجة التطبيقات "&&;واضغط على Enter. (تُلحق "برمجة التطبيقات" إضافة .gs تلقائيًا باسم ملف النص البرمجي).
  5. استبدل الرمز في ملف API.gs الجديد بما يلي:
/**
 * Wrapper function that passes arguments to create a
 * resource sheet describing the characters from Episode IV.
 */
function createPeopleSheetIV() {
  createResourceSheet_('characters', 1, "IV");
}

/**
 * Wrapper function that passes arguments to create a
 * resource sheet describing the characters from Episode V.
 */
function createPeopleSheetV() {
  createResourceSheet_('characters', 2, "V");
}

/**
 * Wrapper function that passes arguments to create a
 * resource sheet describing the characters from Episode VI.
 */
function createPeopleSheetVI() {
  createResourceSheet_('characters', 3, "VI");
}

/** 
 * Creates a formatted sheet filled with user-specified
 * information from the Star Wars API. If the sheet with
 * this data exists, the sheet is overwritten with the API
 * information.
 *
 * @param {string} resourceType The type of resource.
 * @param {number} idNumber The identification number of the film.
 * @param {number} episodeNumber The Star Wars film episode number.
 *   This is only used in the sheet name.
 */
function createResourceSheet_(
    resourceType, idNumber, episodeNumber) { 
  
  // Fetch the basic film data from the API. 
  var filmData = fetchApiResourceObject_(
      "https://swapi.dev/api/films/" + idNumber);

  // Extract the API URLs for each resource so the code can
  // call the API to get more data about each individually.
  var resourceUrls = filmData[resourceType];
  
  // Fetch each resource from the API individually and push
  // them into a new object list.
  var resourceDataList = []; 
  for(var i = 0; i < resourceUrls.length; i++){
    resourceDataList.push(
      fetchApiResourceObject_(resourceUrls[i])
    ); 
  } 
  
  // Get the keys used to reference each part of data within
  // the resources. The keys are assumed to be identical for
  // each object since they're all the same resource type.
  var resourceObjectKeys = Object.keys(resourceDataList[0]);
  
  // Create the sheet with the appropriate name. It
  // automatically becomes the active sheet when it's created.
  var resourceSheet = createNewSheet_(
      "Episode " + episodeNumber + " " + resourceType);
  
  // Add the API data to the new sheet, using each object
  // key as a column header. 
  fillSheetWithData_(resourceSheet, resourceObjectKeys, resourceDataList);
  
  // Format the new sheet using the same styles the
  // 'Quick Formats' menu items apply. These methods all
  // act on the active sheet, which is the one just created.
  formatRowHeader();
  formatColumnHeader();   
  formatDataset();

}
  1. أضِف دوال المساعدة التالية إلى نهاية ملف مشروع النص البرمجي API.gs:
/** 
 * Helper function that retrieves a JSON object containing a
 * response from a public API.
 *
 * @param {string} url The URL of the API object being fetched.
 * @return {object} resourceObject The JSON object fetched
 *   from the URL request to the API.
 */
function fetchApiResourceObject_(url) {
  // Make request to API and get response.
  var response =
    UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
  
  // Parse and return the response as a JSON object.
  var json = response.getContentText();
  var responseObject = JSON.parse(json); 
  return responseObject; 
}

/** 
 * Helper function that creates a sheet or returns an existing
 * sheet with the same name.
 *
 * @param {string} name The name of the sheet.
 * @return {object} The created or existing sheet
 *   of the same name. This sheet becomes active.
 */ 
function createNewSheet_(name) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  
  // Returns an existing sheet if it has the specified
  // name. Activates the sheet before returning.
  var sheet = ss.getSheetByName(name);
  if (sheet) {
    return sheet.activate();
  }
  
  // Otherwise it makes a sheet, set its name, and returns it.
  // New sheets created this way automatically become the active
  // sheet.
  sheet = ss.insertSheet(name); 
  return sheet; 
}

/** 
 * Helper function that adds API data to the sheet.
 * Each object key is used as a column header in the new sheet.
 *
 * @param {object} resourceSheet The sheet object being modified.
 * @param {object} objectKeys The list of keys for the resources.
 * @param {object} resourceDataList The list of API
 *   resource objects containing data to add to the sheet.
 */
function fillSheetWithData_(
    resourceSheet, objectKeys, resourceDataList) {
  // Set the dimensions of the data range being added to the sheet.
  var numRows = resourceDataList.length;
  var numColumns = objectKeys.length;
  
  // Get the resource range and associated values array. Add an
  // extra row for the column headers.
  var resourceRange =
    resourceSheet.getRange(1, 1, numRows + 1, numColumns);
  var resourceValues = resourceRange.getValues(); 
  
  // Loop over each key value and resource, extracting data to
  // place in the 2D resourceValues array.
  for (var column = 0; column < numColumns; column++) {

    // Set the column header.
    var columnHeader = objectKeys[column];
    resourceValues[0][column] = columnHeader;
    
    // Read and set each row in this column.
    for (var row = 1; row < numRows + 1; row++) {
      var resource = resourceDataList[row - 1];
      var value = resource[columnHeader];
      resourceValues[row][column] = value;
    }
  }
  
  // Remove any existing data in the sheet and set the new values.
  resourceSheet.clear()
  resourceRange.setValues(resourceValues);
}
  1. احفظ مشروع النص البرمجي.

مراجعة الرموز

لقد أضفت الكثير من الرموز. لنستعرض كل وظيفة على حدة لفهم آلية عملها:

onOpen()

لقد أضفت هنا بعض عناصر القائمة إلى قائمة Quick formats. لقد أعددت سطر فاصل ثم استخدمت طريقة Menu.addSubMenu(menu) لإنشاء بنية قائمة متداخلة تتضمن ثلاثة عناصر جديدة. تتم إضافة العناصر الجديدة باستخدام طريقة Menu.addItem(caption, functionName).

وظائف المغلّف

تنفّذ عناصر القائمة المضافة جميعها إجراءً مشابهًا: إنها تحاول إنشاء ورقة باستخدام بيانات مستخرَجة من SWAPI. والفرق الوحيد هو أن كل منها يركز على فيلم مختلف.

سيكون من السهل كتابة دالة واحدة لإنشاء الورقة، والطلب من الدالة قبول معلمة لتحديد الفيلم الذي سيتم استخدامه. إلا أن طريقة Menu.addItem(caption, functionName) لا تسمح لك بتمرير المعلّمات إليه عند طلبها من القائمة. إذًا، كيف تجنّب كتابة الرمز نفسه ثلاث مرات؟

الإجابة هي دوال برنامج تضمين. هذه وظائف خفيفة ويمكنك استدعاءها وتتصل فورًا بوظيفة أخرى مع ضبط معلمات معيّنة.

يستخدِم الرمز هنا ثلاث وظائف برامج تضمين: createPeopleSheetIV() وcreatePeopleSheetV() وcreatePeopleSheetVI(). ترتبط عناصر القائمة بهذه الدوال. عند النقر على عنصر في القائمة، يتم تنفيذ دالة برنامج التضمين واستدعاء دالة إنشاء الورقة الرئيسية createResourceSheet_(resourceType, idNumber, episodeNumber) على الفور، مع تمرير المَعلمات المناسبة لعنصر القائمة. وفي هذه الحالة، يعني ذلك أن أداة إنشاء جداول البيانات تنشئ ورقة مليئة ببيانات الأحرف الرئيسية من أحد أفلام Star Wars.

createResourceSheet_(resourceType, idNumber, episodeNumber)

هذه هي أداة إنشاء الأوراق الرئيسية لهذا التمرين. وبمساعدة بعض وظائف المساعد، يحصل على بيانات واجهة برمجة التطبيقات، ويحللها، وينشئ جدول بيانات، ويكتب بيانات واجهة برمجة التطبيقات إلى الورقة، ثم يُنسّق الورقة باستخدام الدوال التي أنشأتها في الأقسام السابقة. لنراجع التفاصيل:

أولاً، تستخدم الدالة fetchApiResourceObject_(url) لطلب واجهة برمجة التطبيقات لاسترداد معلومات الفيلم الأساسية. تتضمن استجابة واجهة برمجة التطبيقات مجموعة من عناوين URL التي يمكن أن يستخدمها الرمز للحصول على مزيد من التفاصيل عن أشخاص محددين (تُعرف هنا باسم الموارد) من الأفلام. يجمع الرمز كل المعلومات في مصفوفة resourceUrls.

بعد ذلك، يستخدم الرمز fetchApiResourceObject_(url) بشكل متكرّر لاستدعاء واجهة برمجة التطبيقات لكل عنوان URL لمصدر في resourceUrls. يتم تخزين النتائج في مصفوفة resourceDataList. كل عنصر في هذه المصفوفة هو كائن يصف حرفًا مختلفًا من الفيلم.

تحتوي كائنات بيانات الموارد على العديد من المفاتيح الشائعة التي يتم ربطها بمعلومات عن ذلك الحرف. على سبيل المثال، يرتبط المفتاح "name&#39؛ باسم الحرف في الفيلم. نفترض أنّ المفاتيح لكل عنصر من عناصر بيانات المورد متطابقة، لأنها تهدف إلى استخدام تركيبات العناصر الشائعة. تحتاج قائمة المفاتيح لاحقًا، لذلك يخزّن الرمز قائمة المفاتيح في resourceObjectKeys باستخدام طريقة JavaScript Object.keys().

بعد ذلك، تستدعي دالة الإنشاء الدالة مساعد createNewSheet_(name) لإنشاء الورقة التي سيتم وضع البيانات الجديدة فيها. يؤدي استدعاء هذه الدالة المساعدة إلى تفعيل الورقة الجديدة أيضًا.

بعد إنشاء الورقة، يتم استدعاء الدالة المساعدة fillSheetWithData_(resourceSheet, objectKeys, resourceDataList) لإضافة جميع بيانات واجهة برمجة التطبيقات إلى الورقة.

وأخيرًا، يتم استدعاء جميع وظائف التنسيق التي أنشأتها سابقًا لتطبيق قواعد التنسيق نفسها على البيانات الجديدة. بما أن الورقة الجديدة هي الورقة النشطة، يمكن للرمز إعادة استخدام هذه الدوال بدون تعديل.

fetchApiResourceObject_(url)

تشبه هذه الوظيفة المساعدة الوظيفة "fetchBookData_(ISBN)" المساعدة في الدرس التطبيقي السابق التعامل مع البيانات. تستغرق الاستجابة عنوان URL المحدّد وتستخدم طريقة UrlFetchApp.fetch(url, params) للحصول على الرد. وبعد ذلك، يتم تحليل الاستجابة إلى كائن JSON باستخدام طريقتَي HTTPResponse.getContextText() وJavaScript JSON.parse(json). يتم بعد ذلك عرض كائن JSON الناتج.

createNewSheet_(name)

وظيفة المساعد هذه بسيطة إلى حدٍّ ما. يتم أولاً التحقق من وجود ورقة بالاسم نفسه في جدول البيانات. إذا كان الأمر كذلك، ستعمل الدالة على تفعيل الورقة وإرجاعها.

في حال عدم توفّر الورقة، ستنشئها الدالة باستخدام Spreadsheet.insertSheet(sheetName) وتفعّلها وتعرِض الورقة الجديدة.

fillSheetWithData_(resourceSheet, objectKeys, resourceDataList)

وظيفة المساعد هذه مسؤولة عن ملء الورقة الجديدة ببيانات واجهة برمجة التطبيقات. ويتم استخدامها كمعلمات في الورقة الجديدة وقائمة مفاتيح الكائنات وقائمة كائنات موارد واجهة برمجة التطبيقات كمعلّمات. يُمثل كل مفتاح عنصر عمودًا في الورقة الجديدة، ويمثّل كل كائن مورد صفًا.

أولاً، تحسب الدالة عدد الصفوف والأعمدة المطلوبة لعرض بيانات واجهة برمجة التطبيقات الجديدة. هذا هو حجم قائمة المفاتيح والمصادر على التوالي. تحدد الدالة بعد ذلك نطاق الناتج (resourceRange) الذي سيتم وضع البيانات فيه، مع إضافة صف إضافي لتثبيت رؤوس الأعمدة. يحمل المتغير resourceValues مصفوفة قيم ثنائية الأبعاد مستخرجة من resourceRange.

تكرِّر الدالة بعد ذلك كل مفتاح عنصر في قائمة objectKeys. يتم ضبط المفتاح كرأس عمود، ثم تمر حلقة ثانية عبر كل كائن مورد. بالنسبة إلى كل زوج (صف أو عمود)، يتم نسخ معلومات واجهة برمجة التطبيقات المقابلة إلى العنصر resourceValues[row][column].

بعد ملء resourceValues، يتم محو جدول البيانات باستخدام Sheet.clear() في حال احتواءه على بيانات من النقرات السابقة على عنصر القائمة. وأخيرًا، تتم كتابة القيم الجديدة إلى الورقة.

النتائج

يمكنك الاطّلاع على نتائج عملك عن طريق إجراء ما يلي:

  1. احفظ مشروع النص البرمجي في محرِّر "برمجة تطبيقات Google"، إذا لم يسبق لك إجراء ذلك.
  2. انقر على عنصر القائمة التنسيقات السريعة &gt؛ إنشاء ورقة أحرف &gt؛ الحلقة الرابعة.

من المفترض أن تظهر النتائج على النحو التالي:

d9c472ab518d8cef.gif

لقد كتبت الآن رمزًا لاستيراد البيانات إلى "جداول بيانات Google" وتنسيقه تلقائيًا.

8- الخلاصة

تهانينا على إكمال هذا الدرس التطبيقي حول الترميز. لقد رأيت بعض خيارات تنسيق "جداول بيانات Google" التي يمكنك تضمينها في مشاريع "برمجة التطبيقات" وأنشأت تطبيقًا مذهلاً يعمل على استيراد مجموعة بيانات كبيرة من واجهة برمجة التطبيقات وتنسيقها.

هل وجدت هذا الدرس التطبيقي مفيدًا؟

نعم لا

ما تعلّمته

  • كيفية تطبيق عمليات تنسيق مختلفة في "جداول بيانات Google" باستخدام "برمجة تطبيقات Google".
  • كيفية إنشاء قوائم فرعية باستخدام الدالة onOpen().
  • طريقة تنسيق قائمة كائنات JSON التي تم جلبها في ورقة بيانات جديدة باستخدام "برمجة التطبيقات".

الخطوات التالية

يعرض لك الدرس التطبيقي التالي حول الترميز في قائمة التشغيل هذه كيفية استخدام "برمجة التطبيقات" لعرض البيانات في رسم بياني وتصدير الرسوم البيانية إلى العروض التقديمية من Google.

ابحث عن الدرس التطبيقي التالي حول الترميز في الرسم البياني وعرض البيانات في "العروض التقديمية من Google".