مقال تقني

المراجع الهيكلية لجداول إكسل في Delphi باستخدام HotXLS

يُقيِّم HotXLS الآن المراجع الهيكلية للجداول، بحيث تُنتج =SUM(Table1[Amount]) رقماً بدلاً من تخطيها. يتعامل المُحلِّل مع Table[Column] وTable[[Column]]، ومديات الأعمدة مثل Table[[Q1]:[Q4]]، ومحددات العناصر [#Data] و[#All] و[#Headers] و[#Totals]، ويحل كلاً منها مقابل نموذج جدول مصنف العمل وقت التحليل بينما يُحفَظ نص الصيغة الأصلي حرفياً عند التنقل ذهاباً وإياباً

شكل واحد غائب عمداً، وهو الشكل الذي يصطدم به الناس أولاً. الاختصار الخاص بالصف الحالي [@Column] غير مدعوم، لسبب بنيوي يستحق الفهم بدلاً من الالتفاف حوله عشوائياً

لماذا لا يكون المرجع الهيكلي مجرد نطاق باسم ودود؟

لأن الاسم المعرَّف يجمّد عنواناً بينما لا يفعل مرجع الجدول ذلك. اكتب DataBlock كاسم يشير إلى Sheet1!$A$2:$D$100 وسيبقى ذلك المستطيل حتى تعيد كتابته. اكتب Sales[Amount] وهذا يعني «عمود Amount في جدول Sales»، أياً كان امتداد ذلك الجدول عندما تُقيَّم الصيغة. أضف عشرين صفاً إلى الجدول وسيغطيها المجموع؛ لا يوجد مرجع يجب تعديله لأنه لم يكن هناك عنوان في الصيغة أصلاً

هذه الخاصية الرمزية هي بالضبط سبب تعذُّر حل المرجع باستبدال نصي. يجب على المُحلِّل أن يجد الجدول بالاسم في مصنف العمل، ويبحث عن العمود بنص رأسه، ويقرر أي الصفوف يغطيها محدد العنصر المطلوب، وينتج مستطيلاً ملموساً. يفعل HotXLS هذا أثناء ترجمة الصيغة عبر نموذج الجدول، وهذا سبب استمرار صيغة كُتبت قبل نمو الجدول في التقييم مقابل امتداد الجدول الحالي

القواعد النحوية التي يحلّها HotXLS

تغطي القواعد النحوية المدعومة في المواصفة نتيجة مستطيلة واحدة، وتستحق الذكر بدقة، لأن توثيق إكسل يعرض مساحة أكبر بكثير مما تنفذه معظم المحركات. يقبل HotXLS [Col] والمتغير المحاط بأقواس [[Col]]، ومحددات العناصر المجردة [#Data] و[#All] و[#Headers] و[#Totals]، والشكل المركَّب [[#Data],[Col]]، ومدى داخل محدد عنصر كـ [[#Data],[Col1]:[Col2]]، ومدى بسيط [Col1]:[Col2]

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

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Cols: TStringList;
begin
  Book := TXLSXWorkbook.Create;
  Cols := TStringList.Create;
  try
    Sheet := Book.Sheets.Add('Sales');
    Cols.Add('Region');
    Cols.Add('Q1');
    Cols.Add('Q2');
    Cols.Add('Amount');
    Sheet.Tables.Add('SalesTable', 'A1:D25', Cols);
    // ... اكتب صف الرأس و24 صف بيانات ...

    Sheet.Cells[27, 4].Formula := 'SUM(SalesTable[Amount])';
    Sheet.Cells[28, 4].Formula := 'SUM(SalesTable[[Q1]:[Q2]])';
    Sheet.Cells[29, 4].Formula := 'COUNTA(SalesTable[[#Data],[Region]])';
    Sheet.Cells[30, 4].Formula := 'ROWS(SalesTable[#All])';

    Book.Recalculate;
    Book.SaveAs('sales.xlsx');
  finally
    Cols.Free;
    Book.Free;
  end;
end;

لماذا استُبعد شكل الصف الحالي عمداً؟

يعني [@Column] و[#This Row] «خلية ذلك العمود في الصف الذي تعيش فيه هذه الصيغة». لذا تعتمد القيمة على موضع الخلية المُقيِّمة، لا على الجدول فقط. هذا نوع مختلف من المراجع: ليس مستطيلاً يمكن للمترجم حله مرة واحدة، بل حلاً لكل خلية يجب إعادته لكل صف تشغله الصيغة

يُعيد HotXLS False من مُحلِّل نطاق الجدول لهذه الأشكال، مما يوجّهها إلى مسار التخطي-دون-قيمة. يُحفظ نص الصيغة ويُكتب مرة أخرى دون تغيير، بحيث يُفتح مصنف عمل يستخدم [@Amount] بشكل صحيح في إكسل بعد تنقل ذهاباً وإياباً عبر تطبيقك؛ فقط القيمة المحسوبة من HotXLS غائبة. بين خيار قيمة غائبة وقيمة محسوبة مقابل صف خاطئ، الغياب هو ما يمكنك اكتشافه

الحل البديل العملي آلي: في مصنف عمل تولّده أنت، اكتب المرجع النسبي المكافئ بنمط A1، وهو ما يخزّنه إكسل داخلياً على أي حال لكثير من المنطق المحصور بنطاق الجدول. في مصنف عمل تعالجه فقط، اترك الصيغة كما هي واقرأ القيمة المخزَّنة مؤقتاً التي خزَّنها إكسل بالفعل، وهو ما يريده عادة خط أنابيب تحميل-وإبلاغ

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Table: TXLSXTable;
  Row: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('sales.xlsx') <> 1 then Exit;
    Sheet := Book.Sheets[1];

    Table := Sheet.Tables.FindByName('SalesTable');
    if Table <> nil then
    begin
      // بحث بأسلوب مجموعة السجلات عبر متن الجدول، نتيجة صف تبدأ من 1
      Row := Table.FindFirst(Sheet, 'Region', 'EMEA');
      while Row > 0 do
      begin
        Log(VarToStr(Sheet.Cells[Row, 4].Value));
        Row := Table.FindNext(Sheet, 'Region', 'EMEA', Row);
      end;
    end;
  finally
    Book.Free;
  end;
end;

ماذا يحدث عندما يغيّر الجدول شكله

تُبطَل المراجع الهيكلية بدلاً من إعادة توجيهها بصمت عندما يزول الشيء الذي تسميه. احذف عموداً وتُبطَل الصيغ التي تشير إلى ذلك العمود بالطريقة نفسها التي يُبطلها بها إكسل؛ احذف الجدول أو أعد تسميته وتُعامَل المراجع إليه بالطريقة نفسها. هذا هو السلوك الصحيح ويعكس تعديل المراجع العادي، الموضح في تعديل مراجع الصيغ عند الإدراج والحذف، حيث تكون مهمة المحرك إبقاء الصيغ صادقة لا إبقاءها تبدو صالحة

نمو الصفوف هو الحالة المعاكسة ولا يحتاج إلى أي تعديل على الإطلاق. بما أن المرجع يسمّي الجدول لا مستطيلاً، فإن إلحاق صفوف داخل نطاق الجدول يوسّع ما يغطيه [#Data] دون لمس صيغة واحدة. هذه هي الخاصية التي تجعل الجداول تستحق الاستخدام في قالب تقرير: يستمر صف المجاميع في جمع كل ما أنتجه الاستيراد، أياً كان عدد الصفوف التي انتهى إليها

انضباط التنقل ذهاباً وإياباً

يحافظ HotXLS على نص الصيغة الأصلي. مصنف عمل حُمِّل بـ SUM(SalesTable[Amount]) يُحفظ بـ SUM(SalesTable[Amount])، لا بالعنوان المحلول SUM(D2:D25). هذا مهم أكثر مما قد يبدو: المستخدم الذي يفتح مخرجاتك في إكسل يتوقع رؤية الصيغة التي كتبها، والعنوان المحلول سيحوّل بصمت نموذجاً ذاتي الصيانة إلى نموذج هش يتوقف عن تغطية الصفوف الجديدة

قدرتان مترابطتان تكملان الصورة. تعريفات الجداول نفسها، بما في ذلك الجداول الخالية من الرؤوس والتعليقات الخاصة بكل جدول، تُحفظ عند التنقل عبر نموذج الجدول الموضح في التحقق من صحة البيانات والتصفية التلقائية وجداول إكسل. وعندما تتشارك خلايا كثيرة نمطاً واحداً، يخزّنها XLSX مرة واحدة كصيغة مشتركة، تُوسَّع وتُعاد إصدارها كما هو موضح في توسيع si للصيغة المشتركة. تمرّ المراجع الهيكلية داخل الصيغ المشتركة عبر كلا المسارين، لذا يجب أن يتصرف كلاهما بشكل صحيح، وهذا ما يحدث

يقرأ HotXLS ويكتب XLS وXLSX وODS من Delphi وC++Builder دون تثبيت إكسل ودون أتمتة Office، ويقيّم الصيغ في محركه الخاص. نموذج الجدول ومحرك الصيغ وواجهة برمجة إعادة الحساب موثَّقة على صفحة مكون HotXLS لجداول البيانات في Delphi