1. مقدمة
مرحبًا بك في الجزء الثالث من قائمة تشغيل codelab حول أساسيات "برمجة تطبيقات Google" مع "جداول بيانات Google".
من خلال إكمال هذا الدرس التطبيقي، يمكنك التعرّف على كيفية استخدام معالجة البيانات والقوائم المخصّصة واسترداد بيانات واجهة برمجة التطبيقات العامة في Apps Script لتحسين تجربتك في "جداول بيانات Google". ستواصل العمل مع الفئات SpreadsheetApp
و Spreadsheet
و Sheet
و Range
التي قدّمتها لك دروس البرمجة السابقة في قائمة التشغيل هذه.
أهداف الدورة التعليمية
- كيفية استيراد البيانات من جدول بيانات شخصي أو مشترك في Drive
- كيفية إنشاء قائمة مخصّصة باستخدام الدالة
onOpen()
- كيفية تحليل قيم بيانات السلسلة النصية ومعالجتها في خلايا "جداول بيانات Google"
- كيفية استرداد بيانات عنصر JSON ومعالجتها من مصدر API عام
قبل البدء
هذا هو الدرس العملي الثالث في قائمة تشغيل "أساسيات برمجة تطبيقات Google" مع "جداول بيانات Google". قبل البدء في هذا الدرس العملي، احرص على إكمال الدروس العملية السابقة:
المتطلبات
- فهم مواضيع "برمجة تطبيقات Google" الأساسية التي تم استكشافها في دروس البرمجة السابقة ضمن قائمة التشغيل هذه
- معرفة أساسية بأداة تعديل رموز برمجة التطبيقات
- معرفة أساسية بـ جداول بيانات Google
- إمكانية قراءة ترميز A1 في "جداول بيانات Google"
- معرفة أساسية بلغة JavaScript وفئة
String
2. إعداد
تتطلّب التمارين الواردة في هذا الدرس العملي توفّر جدول بيانات. اتّبِع الخطوات التالية لإنشاء جدول بيانات لاستخدامه في هذه التمارين:
- أنشئ جدول بيانات في Google Drive. يمكنك إجراء ذلك من واجهة Drive من خلال النقر على جديد > جداول بيانات Google. سيؤدي ذلك إلى إنشاء جدول البيانات الجديد وفتحه. يتم حفظ الملف في مجلد Drive.
- انقر على عنوان جدول البيانات وغيِّره من "جدول بيانات بلا عنوان" إلى "معالجة البيانات والقوائم المخصّصة". يجب أن يبدو جدول البيانات على النحو التالي:
- لفتح "محرِّر النصوص البرمجية"، انقر على الإضافات > برمجة تطبيقات Google.
- انقر على عنوان مشروع Apps Script وغيِّره من "مشروع بدون عنوان" إلى "معالجة البيانات والقوائم المخصّصة". انقر على إعادة تسمية لحفظ تغيير العنوان.
بعد إنشاء جدول بيانات ومشروع فارغَين، ستكون جاهزًا لبدء الدرس التطبيقي. انتقِل إلى القسم التالي لبدء التعرّف على القوائم المخصّصة.
3- نظرة عامة: استيراد البيانات باستخدام عنصر قائمة مخصّص
تمنحك "برمجة تطبيقات Google" إمكانية تحديد قوائم مخصّصة يمكن أن تظهر في "جداول بيانات Google". يمكنك أيضًا استخدام القوائم المخصّصة في "مستندات Google" و"العروض التقديمية من Google" و"نماذج Google". عند تحديد عنصر قائمة مخصّص، يمكنك إنشاء تصنيف نصي وربطه بدالة "برمجة تطبيقات Google" في مشروع النص البرمجي. يمكنك بعد ذلك إضافة القائمة إلى واجهة المستخدم لتظهر في "جداول بيانات Google" باتّباع الخطوات التالية:
عندما ينقر مستخدم على عنصر قائمة مخصّص، يتم تنفيذ دالة Apps Script التي ربطتها به. هذه طريقة سريعة لتشغيل دوال "برمجة التطبيقات" بدون الحاجة إلى فتح محرِّر النصوص البرمجية. ويتيح أيضًا لمستخدمي جدول البيانات الآخرين تنفيذ الرمز البرمجي بدون الحاجة إلى معرفة أي شيء عن طريقة عمله أو طريقة عمل Apps Script. بالنسبة إليهم، هو مجرد عنصر آخر في القائمة.
يتم تحديد عناصر القائمة المخصّصة في دالة onOpen()
المشغّل البسيط، والتي ستتعرّف عليها في القسم التالي.
4. الدالة onOpen()
توفّر المشغّلات البسيطة في "برمجة تطبيقات Google" طريقة لتشغيل رمز "برمجة تطبيقات Google" محدّد استجابةً لشروط أو أحداث معيّنة. عند إنشاء مشغّل، عليك تحديد الحدث الذي يؤدي إلى تشغيله وتوفير دالة Apps Script يتم تنفيذها للحدث.
onOpen()
هو مثال على مشغّل بسيط. يسهل إعدادها، فكل ما عليك فعله هو كتابة دالة في "برمجة تطبيقات Google" باسم onOpen()
، وستنفّذها "برمجة تطبيقات Google" في كل مرة يتم فيها فتح جدول البيانات المرتبط أو إعادة تحميله:
/**
* A special function that runs when the spreadsheet is first
* opened or reloaded. onOpen() is used to add custom menu
* items to the spreadsheet.
*/
function onOpen() {
/* ... */
}
التنفيذ
لننشئ قائمة مخصّصة.
- استبدِل الرمز في مشروع النص البرمجي بما يلي:
/**
* A special function that runs when the spreadsheet is first
* opened or reloaded. onOpen() is used to add custom menu
* items to the spreadsheet.
*/
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Book-list')
.addItem('Load Book-list', 'loadBookList')
.addToUi();
}
- احفظ مشروع النص البرمجي.
مراجعة الرموز البرمجية
لنراجع هذا الرمز لفهم طريقة عمله. في onOpen()
، يستخدم السطر الأول الطريقة getUi()
للحصول على الكائن Ui
الذي يمثّل واجهة المستخدم لجدول البيانات النشط الذي يرتبط به هذا النص البرمجي.
تنشئ الأسطر الثلاثة التالية القائمة (Book-list
)، وتضيف عنصر قائمة (Load Book-list
) إلى تلك القائمة، ثم تضيف القائمة إلى واجهة جدول البيانات. يتم ذلك باستخدام الطرق createMenu(caption)
وaddItem(caption, functionName)
وaddToUi()
على التوالي.
تنشئ الطريقة addItem(caption, functionName)
اتصالاً بين تصنيف عنصر القائمة ودالة "برمجة التطبيقات" التي يتم تنفيذها عند اختيار عنصر القائمة. في هذه الحالة، يؤدي اختيار عنصر القائمة Load Book-list
إلى محاولة "جداول بيانات Google" تنفيذ الدالة loadBookList()
(التي لم يتم إنشاؤها بعد).
النتائج
شغِّل هذه الدالة الآن للتأكّد من أنّها تعمل:
- في "جداول بيانات Google"، أعِد تحميل جدول البيانات. ملاحظة: يؤدي هذا الإجراء عادةً إلى إغلاق علامة التبويب التي تتضمّن محرّر النصوص البرمجية.
- أعِد فتح محرِّر النصوص البرمجية من خلال النقر على الأدوات > محرِّر النصوص البرمجية.
بعد إعادة تحميل جدول البيانات، من المفترض أن تظهر قائمة Book-list
الجديدة على شريط القوائم:
من خلال النقر على قائمة الكتب، يمكنك الاطّلاع على القائمة الناتجة:
ينشئ القسم التالي الرمز البرمجي للدالة loadBookList()
ويقدّم إحدى الطرق التي يمكنك من خلالها التفاعل مع البيانات في "برمجة تطبيقات Google": قراءة جداول بيانات أخرى.
5- استيراد بيانات جدول البيانات
بعد إنشاء قائمة مخصّصة، يمكنك إنشاء دوال يمكن تشغيلها من خلال النقر على عنصر القائمة.
في الوقت الحالي، تحتوي القائمة المخصّصة Book-list
على عنصر قائمة واحد: Load Book-list.
الدالة التي يتم استدعاؤها عند اختيار عنصر القائمة Load Book-list
، loadBookList(),
غير متوفّرة في البرنامج النصي، لذا سيؤدي اختيار قائمة الكتب > تحميل قائمة الكتب إلى ظهور خطأ:
يمكنك حلّ هذا الخطأ من خلال تنفيذ الدالة loadBookList()
.
التنفيذ
نريد أن يملأ عنصر القائمة الجديد جدول البيانات بالبيانات التي سيتم العمل عليها، لذا سننفّذ loadBookList()
لقراءة بيانات الكتب من جدول بيانات آخر ونسخها إلى هذا الجدول:
- أضِف الرمز التالي إلى النص البرمجي ضمن
onOpen()
:
/**
* Creates a template book list based on the
* provided 'codelab-book-list' sheet.
*/
function loadBookList(){
// Gets the active sheet.
var sheet = SpreadsheetApp.getActiveSheet();
// Gets a different spreadsheet from Drive using
// the spreadsheet's ID.
var bookSS = SpreadsheetApp.openById(
"1c0GvbVUDeBmhTpq_A3vJh2xsebtLuwGwpBYqcOBqGvo"
);
// Gets the sheet, data range, and values of the
// spreadsheet stored in bookSS.
var bookSheet = bookSS.getSheetByName("codelab-book-list");
var bookRange = bookSheet.getDataRange();
var bookListValues = bookRange.getValues();
// Add those values to the active sheet in the current
// spreadsheet. This overwrites any values already there.
sheet.getRange(1, 1, bookRange.getHeight(), bookRange.getWidth())
.setValues(bookListValues);
// Rename the destination sheet and resize the data
// columns for easier reading.
sheet.setName("Book-list");
sheet.autoResizeColumns(1, 3);
}
- احفظ مشروع النص البرمجي.
مراجعة الرموز البرمجية
كيف تعمل هذه الوظيفة؟ تستخدم الدالة loadBookList()
طرقًا من الفئات Spreadsheet
وSheet
وRange
التي تم تقديمها في دروس البرمجة السابقة. مع وضع هذه المفاهيم في الاعتبار، يمكنك تقسيم رمز loadBookList()
إلى الأقسام الأربعة التالية:
1: تحديد ورقة الوجهة
يستخدم السطر الأول SpreadsheetApp.getActiveSheet()
للحصول على مرجع لكائن ورقة العمل الحالية وتخزينه في المتغير sheet
. هذا هو جدول البيانات الذي سيتم نسخ البيانات إليه.
2: تحديد بيانات المصدر
تنشئ الأسطر القليلة التالية أربعة متغيّرات تشير إلى البيانات المصدر التي تستردّها:
- يخزّن
bookSS
مرجعًا إلى جدول البيانات الذي تقرأ منه الرموز البيانات. يعثر الرمز على جدول البيانات من خلال رقم تعريف جدول البيانات. في هذا المثال، قدّمنا رقم تعريف جدول بيانات مصدر للقراءة منه، وفتحنا جدول البيانات باستخدام الطريقةSpreadsheetApp.openById(id)
. bookSheet
تخزِّن مرجعًا إلى ورقة ضمنbookSS
تحتوي على البيانات التي تريدها. يحدّد الرمز الورقة التي سيتمّ القراءة منها حسب اسمها،codelab-book-list
.bookRange
تخزّن مرجعًا إلى نطاق من البيانات فيbookSheet
. تعرض الطريقةSheet.getDataRange()
النطاق الذي يحتوي على جميع الخلايا غير الفارغة في ورقة البيانات. وهي طريقة سهلة للتأكّد من حصولك على نطاق يغطي جميع البيانات في ورقة بدون تضمين صفوف وأعمدة فارغة.bookListValues
هو صفيف ثنائي الأبعاد يحتوي على جميع القيم المأخوذة من الخلايا فيbookRange
. تُنشئ الطريقةRange.getValues()
هذه المصفوفة من خلال قراءة البيانات من ورقة المصدر.
3: نسخ البيانات من المصدر إلى الوجهة
ينسخ قسم الرمز التالي بيانات bookListValues
إلى sheet
، ثم يعيد تسمية ورقة البيانات أيضًا:
- يُستخدَم
Sheet.getRange(row, column, numRows, numColumns)
لتحديد مكان نسخ البيانات فيsheet
. - يتم استخدام الطريقتَين
Range.getHeight()
وRange.getWidth()
لقياس حجم البيانات وتحديد نطاق وجهة بالسمات نفسها. - تنسخ الدالة
Range.setValues(values)
مصفوفةbookListValues
الثنائية الأبعاد إلى النطاق الوجهة، مع استبدال أي بيانات موجودة فيه.
4: تنسيق ورقة البيانات الوجهة
يُستخدم الرمز Sheet.setName(name)
لتغيير اسم ورقة الوجهة إلى Book-list
. يستخدم السطر الأخير في الدالة Sheet.autoResizeColumns(startColumn, numColumns)
لتغيير حجم الأعمدة الثلاثة الأولى في ورقة البيانات الوجهة، ما يتيح لك قراءة البيانات الجديدة بسهولة أكبر.
النتائج
يمكنك الاطّلاع على طريقة عمل هذه الدالة. في "جداول بيانات Google"، انقر على قائمة الكتب > تحميل قائمة الكتب لتشغيل الدالة وملء جدول البيانات:
أصبح لديك الآن ورقة تتضمّن قائمة بعناوين الكتب والمؤلفين وأرقام ISBN المكوّنة من 13 رقمًا. في القسم التالي، ستتعرّف على كيفية تعديل البيانات وتحديثها في قائمة الكتب هذه باستخدام معالجة السلاسل والقوائم المخصّصة.
6. نظرة عامة: تنظيف بيانات جدول البيانات
تتوفّر الآن معلومات الكتب في ورقة البيانات. يشير كل صف إلى كتاب معيّن، ويتم إدراج عنوانه ومؤلفه ورقم ISBN في أعمدة منفصلة. ومع ذلك، يمكنك أيضًا ملاحظة بعض المشاكل في هذه البيانات الأولية:
- في بعض الصفوف، يتم وضع العنوان والمؤلف معًا في عمود العنوان، ويكونان مرتبطَين بفاصلة أو السلسلة " by ".
- لا تتضمّن بعض الصفوف عنوان الكتاب أو اسم المؤلف.
في الأقسام التالية، ستصحّح هذه المشاكل من خلال تنظيف البيانات. بالنسبة إلى المشكلة الأولى، عليك إنشاء دوال تقرأ عمود العنوان وتقسّم النص كلما تم العثور على فاصلة أو " by "، مع وضع السلسلتين الفرعيتين الخاصة بالمؤلف والعنوان في العمودين الصحيحين. بالنسبة إلى المشكلة الثانية، ستكتب رمزًا برمجيًا يبحث تلقائيًا عن معلومات الكتب الناقصة باستخدام واجهة برمجة تطبيقات خارجية، ويضيف هذه المعلومات إلى ورقة البيانات.
7. إضافة عناصر القائمة
عليك إنشاء ثلاثة عناصر قائمة للتحكّم في عمليات تنظيف البيانات التي ستنفّذها.
التنفيذ
لنعدّل onOpen()
لتضمين عناصر القائمة الإضافية التي ستحتاج إليها. فعليك إجراء ما يلي:
- في مشروع النص البرمجي، عدِّل الرمز
onOpen()
ليتطابق مع ما يلي:
/**
* A special function that runs when the spreadsheet is first
* opened or reloaded. onOpen() is used to add custom menu
* items to the spreadsheet.
*/
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Book-list')
.addItem('Load Book-list', 'loadBookList')
.addSeparator()
.addItem(
'Separate title/author at first comma', 'splitAtFirstComma')
.addItem(
'Separate title/author at last "by"', 'splitAtLastBy')
.addSeparator()
.addItem(
'Fill in blank titles and author cells', 'fillInTheBlanks')
.addToUi();
}
- احفظ مشروع النص البرمجي.
- في محرّر النصوص البرمجية، اختَر
onOpen
من قائمة الدوال وانقر على تشغيل. سيؤدي ذلك إلى تشغيلonOpen()
لإعادة إنشاء قائمة جدول البيانات بدون الحاجة إلى إعادة تحميل جدول البيانات.
في هذا الرمز الجديد، تنشئ الطريقة Menu.addSeparator()
فاصلًا أفقيًا في القائمة للحفاظ على تنظيم مجموعات عناصر القائمة ذات الصلة بشكل مرئي. تتم بعد ذلك إضافة عناصر القائمة الجديدة أسفلها، مع التصنيفات Separate title/author at first comma
وSeparate title/author at last "by"
وFill in blank titles and author cells
.
النتائج
في جدول البيانات، انقر على قائمة Book-list
لعرض عناصر القائمة الجديدة:
سيؤدي النقر على هذه العناصر الجديدة إلى حدوث خطأ لأنّك لم تنفّذ وظائفها المقابلة، لذا سنفعل ذلك في الخطوة التالية.
8. تقسيم النص حسب الفواصل
تحتوي مجموعة البيانات التي استوردتها إلى جدول البيانات على بعض الخلايا التي تم فيها دمج المؤلف والعنوان بشكل غير صحيح في خلية واحدة باستخدام فاصلة:
يُعدّ تقسيم السلاسل النصية إلى أعمدة منفصلة مهمة شائعة في جداول البيانات. توفّر "جداول بيانات Google" الدالة SPLIT()
التي تقسم السلاسل إلى أعمدة. ومع ذلك، غالبًا ما تتضمّن مجموعات البيانات مشاكل لا يمكن حلّها بسهولة باستخدام الدوال المضمّنة في "جداول بيانات Google". في هذه الحالات، يمكنك كتابة رمز Apps Script لتنفيذ العمليات المعقّدة اللازمة لتنظيف بياناتك وتنظيمها.
ابدأ بتنظيف بياناتك من خلال تنفيذ دالة باسم splitAtFirstComma()
تقسم المؤلف والعنوان إلى خليتَيهما عند العثور على فواصل.
يجب أن تتّخذ الدالة splitAtFirstComma()
الخطوات التالية:
- الحصول على النطاق الذي يمثّل الخلايا المحدّدة حاليًا
- تحقَّق ممّا إذا كانت الخلايا في النطاق تحتوي على فاصلة.
- عند العثور على فواصل، قسِّم السلسلة إلى سلسلتَين فرعيتَين (فقط) في موضع الفاصلة الأولى. لتسهيل الأمر، يمكنك افتراض أنّ أي فاصلة تشير إلى نمط السلسلة "[المؤلفون]، [العنوان]". يمكنك أيضًا افتراض أنّه إذا ظهرت فواصل متعددة في الخلية، من المناسب التقسيم عند الفاصلة الأولى في السلسلة.
- اضبط السلاسل الفرعية كمحتوى جديد لخلايا العنوان والمؤلف المعنيّة.
التنفيذ
لتنفيذ هذه الخطوات، ستستخدم طرق خدمة جداول البيانات نفسها التي استخدمتها من قبل، ولكن ستحتاج أيضًا إلى استخدام JavaScript لمعالجة بيانات السلسلة. يُرجى تنفيذ ما يلي:
- في "محرِّر برمجة التطبيقات"، أضِف الدالة التالية إلى نهاية مشروع النص البرمجي:
/**
* Reformats title and author columns by splitting the title column
* at the first comma, if present.
*/
function splitAtFirstComma(){
// Get the active (currently highlighted) range.
var activeRange = SpreadsheetApp.getActiveRange();
var titleAuthorRange = activeRange.offset(
0, 0, activeRange.getHeight(), activeRange.getWidth() + 1);
// Get the current values of the selected title column cells.
// This is a 2D array.
var titleAuthorValues = titleAuthorRange.getValues();
// Update values where commas are found. Assumes the presence
// of a comma indicates an "authors, title" pattern.
for (var row = 0; row < titleAuthorValues.length; row++){
var indexOfFirstComma =
titleAuthorValues[row][0].indexOf(", ");
if(indexOfFirstComma >= 0){
// Found a comma, so split and update the values in
// the values array.
var titlesAndAuthors = titleAuthorValues[row][0];
// Update the title value in the array.
titleAuthorValues[row][0] =
titlesAndAuthors.slice(indexOfFirstComma + 2);
// Update the author value in the array.
titleAuthorValues[row][1] =
titlesAndAuthors.slice(0, indexOfFirstComma);
}
}
// Put the updated values back into the spreadsheet.
titleAuthorRange.setValues(titleAuthorValues);
}
- احفظ مشروع النص البرمجي.
مراجعة الرموز البرمجية
لنراجع الرمز الجديد الذي يتألف من ثلاثة أقسام رئيسية:
1: استرداد قيم العناوين المميّزة
تحدّد الأسطر الثلاثة الأولى ثلاثة متغيرات تشير إلى البيانات الحالية في ورقة البيانات:
- يمثّل
activeRange
النطاق الذي يحدّده المستخدم حاليًا عندما يتم استدعاء الدالةsplitAtFirstComma()
. لتبسيط هذا التمرين، يمكننا افتراض أنّ المستخدم لا ينفّذ هذا الإجراء إلا عند تمييز الخلايا في العمود A. - يمثّل
titleAuthorRange
نطاقًا جديدًا يغطي الخلايا نفسها التي يغطيهاactiveRange
، ولكنّه يتضمّن أيضًا عمودًا إضافيًا على اليسار. يتم إنشاءtitleAuthorRange
باستخدام الطريقةRange.offset(rowOffset, columnOffset, numRows, numColumns)
. يحتاج الرمز إلى هذا النطاق الموسّع لأنّه يحتاج إلى مكان لوضع أي مؤلفين يعثر عليهم في عمود العنوان. titleAuthorValues
هي مصفوفة ثنائية الأبعاد من البيانات المستخرَجة منtitleAuthorRange
باستخدامRange.getValues()
.
2: فحص كل عنوان وتقسيمه عند أول فاصلة يتم العثور عليها
يفحص القسم التالي القيم في titleAuthorValues
للعثور على فواصل. يتم استخدام حلقة JavaScript For لفحص جميع القيم في العمود الأول من titleAuthorValues
. عند العثور على سلسلة فرعية تتضمّن فاصلة (", "
) باستخدام طريقة JavaScript String indexOf()، ينفّذ الرمز ما يلي:
- يتم نسخ قيمة سلسلة الخلية إلى المتغير
titlesAndAuthors
. - يتم تحديد موضع الفاصلة باستخدام طريقة JavaScript String indexOf().
- يتم استدعاء طريقة JavaScript String slice() مرتين للحصول على السلسلة الفرعية قبل الفاصلة المحدِّدة والسلسلة الفرعية بعدها.
- يتم نسخ السلاسل الفرعية مرة أخرى إلى مصفوفة titleAuthorValues الثنائية الأبعاد، ما يؤدي إلى استبدال القيم الحالية في هذا الموضع. بما أنّنا نفترض نمط "[المؤلفون]، [العنوان]"، يتم عكس ترتيب السلسلتَين الفرعيتَين لوضع العنوان في العمود الأول والمؤلفين في العمود الثاني.
ملاحظة: عندما لا يعثر الرمز على فاصلة، يترك البيانات في الصف بدون تغيير.
3: نسخ القيم الجديدة مرة أخرى إلى ورقة البيانات
بعد فحص جميع قيم خلايا العنوان، يتم نسخ مصفوفة titleAuthorValues الثنائية الأبعاد المعدَّلة مرة أخرى إلى جدول البيانات باستخدام الطريقة Range.setValues(values)
.
النتائج
يمكنك الآن الاطّلاع على تأثير وظيفة splitAtFirstComma()
عمليًا. جرِّب تشغيلها من خلال اختيار عنصر القائمة فصل العنوان/المؤلف عند الفاصلة الأولى بعد اختيار...
...خلية واحدة:
...أو عدة خلايا:
لقد أنشأت الآن دالة في Apps Script تعالج بيانات "جداول بيانات Google". بعد ذلك، عليك تنفيذ دالة التقسيم الثانية.
9- تقسيم النص حسب المحددات "by"
بالنظر إلى البيانات الأصلية، يمكنك ملاحظة مشكلة أخرى. كما أنّ بعض تنسيقات البيانات تعرض العناوين والمؤلفين في خلية واحدة بالتنسيق "[المؤلفون]، [العنوان]"، تعرض خلايا أخرى المؤلف والعنوان بالتنسيق "[العنوان] للمؤلف [المؤلفون]":
التنفيذ
يمكنك حلّ هذه المشكلة باستخدام الأسلوب نفسه من القسم الأخير، وذلك بإنشاء دالة باسم splitAtLastBy()
. تتشابه هذه الدالة مع الدالة splitAtFirstComma()
في الوظيفة، والفرق الوحيد هو أنّها تبحث عن نمط مختلف قليلاً من النص. نفِّذ هذه الدالة باتّباع الخطوات التالية:
- في "محرِّر برمجة التطبيقات"، أضِف الدالة التالية إلى نهاية مشروع النص البرمجي:
/**
* Reformats title and author columns by splitting the title column
* at the last instance of the string " by ", if present.
*/
function splitAtLastBy(){
// Get the active (currently highlighted) range.
var activeRange = SpreadsheetApp.getActiveRange();
var titleAuthorRange = activeRange.offset(
0, 0, activeRange.getHeight(), activeRange.getWidth() + 1);
// Get the current values of the selected title column cells.
// This is a 2D array.
var titleAuthorValues = titleAuthorRange.getValues();
// Update values where " by " substrings are found. Assumes
// the presence of a " by " indicates a "title by authors"
// pattern.
for(var row = 0; row < titleAuthorValues.length; row++){
var indexOfLastBy =
titleAuthorValues[row][0].lastIndexOf(" by ");
if(indexOfLastBy >= 0){
// Found a " by ", so split and update the values in
// the values array.
var titlesAndAuthors = titleAuthorValues[row][0];
// Update the title value in the array.
titleAuthorValues[row][0] =
titlesAndAuthors.slice(0, indexOfLastBy);
// Update the author value in the array.
titleAuthorValues[row][1] =
titlesAndAuthors.slice(indexOfLastBy + 4);
}
}
// Put the updated values back into the spreadsheet.
titleAuthorRange.setValues(titleAuthorValues);
}
- احفظ مشروع النص البرمجي.
مراجعة الرموز البرمجية
هناك بعض الاختلافات الرئيسية بين هذه التعليمات البرمجية وsplitAtFirstComma()
:
- يتم استخدام السلسلة الفرعية "
by
" كفاصل للسلسلة، بدلاً من ",
". - في هذا المثال، يتم استخدام طريقة JavaScript
String.lastIndexOf(substring)
بدلاً منString.indexOf(substring)
. وهذا يعني أنّه إذا كانت هناك سلاسل فرعية متعددة "by
" في السلسلة الأولية، سيتم افتراض أنّ جميع السلاسل الفرعية "by
" ما عدا الأخيرة هي جزء من العنوان. - بعد تقسيم السلسلة، يتم ضبط السلسلة الفرعية الأولى كعنوان والثانية كمؤلف (هذا الترتيب معاكس للترتيب في
splitAtFirstComma()
).
النتائج
يمكنك الآن الاطّلاع على تأثير وظيفة splitAtLastBy()
عمليًا. جرِّب تشغيلها من خلال اختيار عنصر القائمة فصل العنوان/المؤلف عند آخر "بواسطة" بعد اختيار...
...خلية واحدة:
...أو عدة خلايا:
لقد أكملت هذا القسم من الدرس التطبيقي حول الترميز. يمكنك الآن استخدام "برمجة التطبيقات" لقراءة بيانات السلسلة وتعديلها في ورقة، واستخدام قوائم مخصّصة لتنفيذ أوامر مختلفة في "برمجة التطبيقات".
في القسم التالي، ستتعرّف على كيفية تحسين مجموعة البيانات هذه بشكل أكبر من خلال ملء الخلايا الفارغة ببيانات مأخوذة من واجهة برمجة تطبيقات عامة.
10. نظرة عامة: الحصول على بيانات من واجهات برمجة التطبيقات العامة
حتى الآن، عدّلت مجموعة البيانات لإصلاح بعض المشاكل في تنسيق العناوين والمؤلفين، ولكن لا تزال مجموعة البيانات تفتقد بعض المعلومات، كما هو موضّح في الخلايا أدناه:
لا يمكنك الحصول على البيانات الناقصة باستخدام عمليات السلسلة على البيانات المتوفّرة لديك حاليًا. بدلاً من ذلك، عليك الحصول على البيانات الناقصة من مصدر آخر. يمكنك إجراء ذلك في Apps Script من خلال طلب معلومات من واجهات برمجة التطبيقات الخارجية التي يمكنها تقديم بيانات إضافية.
واجهات برمجة التطبيقات هي واجهات برمجة التطبيقات. وهو مصطلح عام، ولكنّه يشير بشكل أساسي إلى خدمة يمكن لبرامجك ونصوصك البرمجية طلبها للحصول على معلومات أو اتّخاذ إجراءات معيّنة. في هذا القسم، يمكنك استدعاء واجهة برمجة تطبيقات متاحة للجميع لطلب معلومات عن الكتب يمكنك إدراجها في الخلايا الفارغة في ورقة البيانات.
يعلّمك هذا القسم كيفية:
- طلب بيانات الكتب من مصدر خارجي لواجهة برمجة التطبيقات
- استخرِج معلومات العنوان والمؤلف من البيانات التي تم إرجاعها واكتبها في جدول البيانات.
11. استرجاع البيانات الخارجية باستخدام UrlFetch
قبل الخوض في الرموز البرمجية التي تعمل مباشرةً مع جدول البيانات، يمكنك التعرّف على كيفية استخدام واجهات برمجة التطبيقات الخارجية في "برمجة تطبيقات Google" من خلال إنشاء دالة مساعدة مخصّصة لطلب معلومات الكتب من واجهة برمجة التطبيقات Open Library العامة.
تأخذ دالة المساعدة، fetchBookData_(ISBN)
، رقم ISBN مكوّنًا من 13 رقمًا كمعلَمة وتعرض بيانات حول هذا الكتاب. يتصل هذا التطبيق بواجهة برمجة التطبيقات Open Library API ويسترد المعلومات منها، ثم يحلّل عنصر JSON الذي تم عرضه.
التنفيذ
نفِّذ دالة المساعد هذه باتّباع الخطوات التالية:
- في محرِّر "برمجة تطبيقات Google"، أضِف الرمز التالي إلى نهاية النص البرمجي:
/**
* Helper function to retrieve book data from the Open Library
* public API.
*
* @param {number} ISBN - The ISBN number of the book to find.
* @return {object} The book's data, in JSON format.
*/
function fetchBookData_(ISBN){
// Connect to the public API.
var url = "https://openlibrary.org/api/books?bibkeys=ISBN:"
+ ISBN + "&jscmd=details&format=json";
var response = UrlFetchApp.fetch(
url, {'muteHttpExceptions': true});
// Make request to API and get response before this point.
var json = response.getContentText();
var bookData = JSON.parse(json);
// Return only the data we're interested in.
return bookData['ISBN:' + ISBN];
}
- احفظ مشروع النص البرمجي.
مراجعة الرموز البرمجية
ينقسم هذا الرمز إلى قسمَين رئيسيَّين:
1: طلب البيانات من واجهة برمجة التطبيقات
في السطرَين الأولَين، تتصل fetchBookData_(ISBN)
بواجهة Open Library API العامة باستخدام نقطة نهاية عنوان URL الخاصة بواجهة برمجة التطبيقات وخدمة جلب عناوين URL في "برمجة تطبيقات Google".
المتغيّر url
هو مجرد سلسلة عنوان URL، مثل عنوان ويب. يشير إلى موقع جغرافي على خوادم Open Library. يتضمّن أيضًا ثلاث مَعلمات (bibkeys
وjscmd
وformat
) تُعلم خوادم Open Library بالمعلومات التي تطلبها وكيفية تنظيم الردّ. في هذه الحالة، عليك تقديم رقم ISBN الخاص بالكتاب وطلب عرض معلومات تفصيلية بتنسيق JSON.
بعد إنشاء سلسلة عنوان URL، يرسل الرمز طلبًا إلى الموقع الجغرافي ويتلقّى ردًا. يتم ذلك باستخدام الطريقة UrlFetchApp.fetch(url, params)
. يرسل طلب معلومات إلى عنوان URL خارجي تقدّمه ويخزّن الردّ الناتج في المتغيّر response
. بالإضافة إلى عنوان URL، يضبط الرمز المَعلمة الاختيارية muteHttpExceptions
على true
. يعني هذا الإعداد أنّ الرمز لن يتوقف إذا نتج عن الطلب خطأ في واجهة برمجة التطبيقات. بدلاً من ذلك، يتم عرض استجابة الخطأ.
يعرض الطلب عنصر HTTPResponse
يتم تخزينه في المتغيّر response
. تتضمّن استجابات HTTP رمز استجابة وعناوين HTTP ومحتوى الاستجابة الرئيسي. المعلومات المهمة هنا هي محتوى JSON الرئيسي، لذا يجب أن يستخرج الرمز هذا المحتوى ثم يحلّل JSON للعثور على المعلومات المطلوبة وعرضها.
2: تحليل الردّ من واجهة برمجة التطبيقات وعرض المعلومات المطلوبة
في أسطر الرمز الثلاثة الأخيرة، تعرض الدالة HTTPResponse.getContentText()
المحتوى الرئيسي للرد كسلسلة. هذه السلسلة بتنسيق JSON، ولكن تحدّد Open Library API المحتوى والتنسيق الدقيقَين. تحوّل الطريقة JSON.parse(jsonString)
سلسلة JSON إلى كائن JavaScript، ما يتيح استخراج أجزاء مختلفة من البيانات بسهولة. وأخيرًا، تعرض الدالة البيانات المقابلة لرقم ISBN الخاص بالكتاب.
النتائج
بعد تنفيذ fetchBookData_(ISBN)
، يمكن لوظائف أخرى في الرمز البرمجي العثور على معلومات عن أي كتاب باستخدام رقم ISBN الخاص به. ستستخدم هذه الدالة للمساعدة في ملء الخلايا في جدول البيانات.
12. كتابة بيانات واجهة برمجة التطبيقات في جدول بيانات
يمكنك الآن تنفيذ الدالة fillInTheBlanks()
التي تنفّذ ما يلي:
- حدِّد بيانات العنوان والمؤلف المفقودة ضمن نطاق البيانات النشط.
- استرداد البيانات الناقصة لكتاب معيّن من خلال استدعاء Open Library API باستخدام طريقة المساعدة
fetchBookData_(ISBN)
- عدِّل قيم العنوان أو المؤلف غير المتوفّرة في الخلايا الخاصة بها.
التنفيذ
نفِّذ هذه الدالة الجديدة باتّباع الخطوات التالية:
- في "محرِّر برمجة التطبيقات"، أضِف الرمز التالي إلى نهاية مشروع النص البرمجي:
/**
* Fills in missing title and author data using Open Library API
* calls.
*/
function fillInTheBlanks(){
// Constants that identify the index of the title, author,
// and ISBN columns (in the 2D bookValues array below).
var TITLE_COLUMN = 0;
var AUTHOR_COLUMN = 1;
var ISBN_COLUMN = 2;
// Get the existing book information in the active sheet. The data
// is placed into a 2D array.
var dataRange = SpreadsheetApp.getActiveSpreadsheet()
.getDataRange();
var bookValues = dataRange.getValues();
// Examine each row of the data (excluding the header row).
// If an ISBN is present, and a title or author is missing,
// use the fetchBookData_(isbn) method to retrieve the
// missing data from the Open Library API. Fill in the
// missing titles or authors when they're found.
for(var row = 1; row < bookValues.length; row++){
var isbn = bookValues[row][ISBN_COLUMN];
var title = bookValues[row][TITLE_COLUMN];
var author = bookValues[row][AUTHOR_COLUMN];
if(isbn != "" && (title === "" || author === "") ){
// Only call the API if you have an ISBN number and
// either the title or author is missing.
var bookData = fetchBookData_(isbn);
// Sometimes the API doesn't return the information needed.
// In those cases, don't attempt to update the row.
if (!bookData || !bookData.details) {
continue;
}
// The API might not return a title, so only fill it in
// if the response has one and if the title is blank in
// the sheet.
if(title === "" && bookData.details.title){
bookValues[row][TITLE_COLUMN] = bookData.details.title;
}
// The API might not return an author name, so only fill it in
// if the response has one and if the author is blank in
// the sheet.
if(author === "" && bookData.details.authors
&& bookData.details.authors[0].name){
bookValues[row][AUTHOR_COLUMN] =
bookData.details.authors[0].name;
}
}
}
// Insert the updated book data values into the spreadsheet.
dataRange.setValues(bookValues);
}
- احفظ مشروع النص البرمجي.
مراجعة الرموز البرمجية
تنقسم هذه التعليمات البرمجية إلى ثلاثة أقسام:
1: قراءة معلومات الكتاب الحالي
تحدّد الأسطر الثلاثة الأولى من الدالة الثوابت للمساعدة في جعل الرمز أكثر قابلية للقراءة. في السطرَين التاليَين، يتم استخدام المتغيّر bookValues
للاحتفاظ بنسخة محلية من معلومات كتاب ورقة البيانات. سيقرأ الرمز المعلومات من bookValues
، ويستخدم واجهة برمجة التطبيقات لملء المعلومات الناقصة، ثم يعيد كتابة هذه القيم في جدول البيانات.
2: استرجاع المعلومات الناقصة باستخدام الدالة المساعدة
يتكرّر الرمز البرمجي على كل صف في bookValues
للعثور على العناوين أو المؤلّفين الناقصين. لتقليل عدد طلبات البيانات من واجهة برمجة التطبيقات مع تحسين الكفاءة، لا يطلب الرمز البيانات من واجهة برمجة التطبيقات إلا إذا تحققت الشروط التالية:
- يحتوي عمود رقم ISBN الخاص بالصف على قيمة.
- إما أنّ خلية العنوان أو خلية المؤلف في الصف فارغة.
إذا كانت الشروط صحيحة، يستدعي الرمز البرمجي واجهة برمجة التطبيقات باستخدام الدالة المساعدة fetchBookData_(isbn)
التي نفّذتها سابقًا، ويخزّن النتيجة في المتغيّر bookData
. يجب أن تتضمّن الآن المعلومات الناقصة التي تريد إدراجها في الورقة.
المهمة الوحيدة المتبقية هي إضافة معلومات bookData
إلى جدول البيانات. ومع ذلك، هناك تحذير. في بعض الأحيان، لا تتضمّن واجهات برمجة التطبيقات المتاحة للجميع، مثل Open Library Book API، المعلومات التي تطلبها، أو قد تواجه أحيانًا مشكلة أخرى تمنعها من تقديم المعلومات. إذا افترضت أنّ كل طلب بيانات من واجهة برمجة التطبيقات سينجح، لن يكون الرمز البرمجي قويًا بما يكفي للتعامل مع الأخطاء غير المتوقّعة.
للتأكّد من أنّ الرمز البرمجي يمكنه التعامل مع أخطاء واجهة برمجة التطبيقات، يجب أن يتحقّق الرمز البرمجي من أنّ استجابة واجهة برمجة التطبيقات صالحة قبل محاولة استخدامها. بعد أن يحتوي الرمز على bookData
، يتم إجراء عملية تحقّق بسيطة للتأكّد من توفّر bookData
وbookData.details
قبل محاولة القراءة منهما. إذا كان أيّ منهما غير متوفّر، يعني ذلك أنّ واجهة برمجة التطبيقات لم تتضمّن البيانات التي أردتها. في هذه الحالة، يطلب الأمر continue
من الرمز البرمجي تخطّي هذا الصف، ولا يمكنك ملء الخلايا الناقصة، ولكن على الأقل لن يتعطّل النص البرمجي.
3: إعادة كتابة المعلومات المعدَّلة في ورقة البيانات
يحتوي الجزء الأخير من الرمز على عمليات تحقّق مشابهة للتأكّد من أنّ واجهة برمجة التطبيقات تعرض معلومات العنوان والمؤلف. لا يعدّل الرمز البرمجي مصفوفة bookValues
إلا إذا كانت خلية العنوان أو المؤلف الأصلية فارغة وعرضت واجهة برمجة التطبيقات قيمة يمكنك وضعها هناك.
يتم إنهاء الحلقة بعد فحص جميع الصفوف في ورقة البيانات. الخطوة الأخيرة هي إعادة كتابة مصفوفة bookValues
المعدَّلة الآن إلى جدول البيانات باستخدام Range.setValues(values)
.
النتائج
يمكنك الآن إنهاء عملية تنظيف بيانات الكتب. فعليك إجراء ما يلي:
- إذا لم تكن قد فعلت ذلك بعد، حدِّد النطاق A2:A15 في ورقة البيانات، ثم انقر على قائمة الكتب > فصل العنوان/المؤلف عند الفاصلة الأولى لحلّ مشاكل الفواصل.
- إذا لم يسبق لك إجراء ذلك، حدِّد النطاق A2:A15 في ورقة البيانات، ثم انقر على قائمة الكتب > فصل العنوان/المؤلف عند آخر كلمة "بواسطة" لإصلاح المشاكل المتعلقة بكلمة "بواسطة".
- لملء جميع الخلايا المتبقية، اختَر قائمة الكتب > ملء خلايا العناوين والمؤلفين الفارغة:
13. الخاتمة
تهانينا على إكمال هذا الدرس العملي. لقد تعلّمت كيفية إنشاء قوائم مخصّصة لتفعيل أجزاء مختلفة من رمز Apps Script. لقد تعرّفت أيضًا على كيفية استيراد البيانات إلى "جداول بيانات Google" باستخدام خدمات Apps Script وواجهات برمجة التطبيقات المتاحة للجميع. هذه عملية شائعة في معالجة جداول البيانات، وتسمح لك خدمة "برمجة تطبيقات Google" باستيراد البيانات من مجموعة كبيرة من المصادر. أخيرًا، تعرّفت على كيفية استخدام خدمات "برمجة تطبيقات Google" وJavaScript لقراءة بيانات جداول البيانات ومعالجتها وإدراجها.
هل كان هذا الدرس التطبيقي العملي مفيدًا؟
ما تعلّمته
- كيفية استيراد البيانات من جدول بيانات Google
- كيفية إنشاء قائمة مخصّصة في الدالة
onOpen()
- كيفية تحليل قيم بيانات السلسلة ومعالجتها
- كيفية طلب بيانات من واجهات برمجة التطبيقات العامة باستخدام خدمة جلب عناوين URL
- كيفية تحليل بيانات عنصر JSON التي تم استردادها من مصدر واجهة برمجة تطبيقات عامة
الخطوات التالية
يتناول الدرس التطبيقي التالي في قائمة التشغيل هذه المزيد من التفاصيل حول كيفية تنسيق البيانات داخل جدول بيانات.
يمكنك العثور على الدرس التطبيقي التالي في تنسيق البيانات.