يستطيع HotXLS تقييم صيغة مثل =[Rates.xlsx]FX!B4*C10 مقابل مصنف آخر مفتوح في الذاكرة، لا مقابل قيمة مخزَّنة مؤقتًا وقديمة. تُسجِّل المصنف الثاني بالاسم عبر RegisterExternalWorkbook، وكل عملية إعادة حساب تقرأ الخلايا المُشار إليها مباشرة من ذلك الكائن. أما إلغاء تسجيله فيُرجع التقييم إلى ذاكرة التخزين المؤقت للروابط الخارجية التي يحملها الملف بالفعل
وهذا يسد فجوة محددة ومزعجة. فمصنفات Excel تشير إلى بعضها البعض بشكل روتيني: جدول أسعار، أو دليل حسابات، أو قائمة أسعار يحافظ عليها فريق آخر. وعندما تُفتح مثل هذا الملف بمكتبة بدلاً من Excel، تُحل تلك المراجع عادة إلى أي قيم خُزِّنت مؤقتًا آخر مرة أعاد فيها Excel الحساب، وقد يكون ذلك منذ أشهر، ولا يُصلح ذلك أي قدر من إعادة الحساب لأن البيانات ببساطة غير موجودة
كيف يبدو مرجع عبر المصنفات داخل الملف؟
لا يُخزَّن المرجع الخارجي كالنص الذي تراه في شريط الصيغة. يحتفظ المصنف بجدول للكتب الداعمة، وتشير كل رمزة صيغة إلى فهرس في ذلك الجدول، ويحمل جزء منفصل من القيم المخزَّنة مؤقتًا آخر نتيجة معروفة لكل خلية مُشار إليها. ولهذا السبب لا يزال ملف مفتوح دون مرافقيه يُظهر أرقامًا
ولتحليل الصيغة النصية دقائقه الخاصة. يعامل المحلل اللفظي اسم كتاب بين قوسين كجزء من مُعرِّف واحد، بحيث يصبح [Book.xlsx]Sheet!A1 رمزة واحدة بدلاً من قوس غير متوازن يتبعه مرجع ورقة. ثم تُطبَّع الأسماء للبحث: علامات الاقتباس، وبادئات المسار، وامتداد الملف، وصيغة الفهرس الرقمي، كلها تنهار إلى اسم أساسي بأحرف كبيرة، بحيث يُحل 'C:\Rates\[Rates.xlsx]FX'!B4 و [rates.xlsx]FX!B4 إلى الكتاب المُسجَّل نفسه
تسجيل مصنف وإعادة الحساب
التسجيل بالاسم، والاسم هو الاسم الذي يظهر في صيغ المصنف الذي يقوم بالإشارة:
uses
lxHandleX;
var
Main, Rates: TXLSXWorkbook;
begin
Main := TXLSXWorkbook.Create;
Rates := TXLSXWorkbook.Create;
try
if (Main.Open('valuation.xlsx') <> 1) or
(Rates.Open('rates.xlsx') <> 1) then
Exit;
// الصيغ في valuation.xlsx التي تقول [Rates.xlsx]... تُقرأ الآن
// من الكائن الحي بدلاً من القيم الخارجية المخزَّنة مؤقتًا
Main.RegisterExternalWorkbook('Rates.xlsx', Rates);
Main.Recalculate;
Writeln(VarToStr(Main.Sheets[0].Cells[10, 3].Value));
// غيّر المصدر وأعد الحساب مرة أخرى: القيمة الجديدة تنتقل عبر الصيغة
Rates.Sheets[0].Cells[4, 2].Value := 1.0842;
Main.Recalculate;
Writeln(VarToStr(Main.Sheets[0].Cells[10, 3].Value));
finally
Main.UnregisterExternalWorkbook('Rates.xlsx');
Rates.Free;
Main.Free;
end;
end;
يحمل التسجيل مرجعًا ضعيفًا. فـ HotXLS لا يمتلك المصنف المُسجَّل ولن يحرره، مما يعني أن دورة الحياة مسؤوليتك أنت وأن الترتيب مهم: ألغِ التسجيل قبل تحرير مصنف المصدر، أو على الأقل لا تُعِد الحساب بعد تحريره
ماذا يحدث عندما لا يكون كتاب مُسجَّلاً؟
يرجع التقييم إلى ذاكرة التخزين المؤقت للروابط الخارجية المخزَّنة في الملف، وهو بالضبط سلوك مصنف مفتوح دون مرافقيه. وذلك الرجوع هو سبب كون إلغاء التسجيل آمنًا لا مُدمِّرًا
والسلوك بعد إلغاء التسجيل يستحق ذكره بدقة، لأنه يفاجئ الناس. فعندما لا يمكن حل مرجع لا من كتاب مُسجَّل ولا من ذاكرة التخزين المؤقت، ينتج التقييم خطأً ولا يُكتب ذلك الخطأ مرة أخرى في الخلية. بل تحتفظ الخلية بآخر قيمة محسوبة لها. أعِد تسجيل المصدر وأعِد الحساب، وتتحدث القيمة مرة أخرى
وقاعدة الاحتفاظ عند الفشل هذه مقصودة. فالبديل، وهو كتابة قيمة خطأ في كل خلية تابعة فور عدم توفر مصدر، كان سيحوّل جدول أسعار مفقودًا مؤقتًا إلى مصنف مليء بعلامات خطأ يجب على عملية إعادة حساب ناجحة لاحقة إصلاحها. والاحتفاظ بآخر قيمة سليمة يعني أن خط أنابيب متوقفًا يترك مستندًا لا يزال يُقرأ بمنطقية
الانتشار القذر يتوقف عند حدود المصنف
تحرير خلية في المصدر المُسجَّل لا يُعلِّم الخلايا التابعة في المصنف الرئيسي كقذرة. فإعادة الحساب التزايدية تتبع الاعتماديات داخل مصنف واحد؛ ولا تراقب عبر الحدود. ويتصرف Excel بالطريقة نفسها، ولهذا تتحدث مراجعه الخارجية عند الفتح أو عند تحديث صريح لا باستمرار
والنتيجة العملية أن تغيير قيمة مصدر يتطلب إعادة حساب صريحة للمصنف المُشير، كما في المثال أعلاه. وإذا كان تطبيقك يحرر الكتابين معًا داخل حلقة، أعِد الحساب مرة واحدة في النهاية بدلاً من بعد كل تحرير؛ فالمحرك التزايدي الموصوف في إعادة الحساب التزايدية ومخطط الاعتمادية يؤدي عندئذ أقل قدر من العمل داخل كل مصنف
ثلاثة أشكال تناسب هذه الميزة
التوحيد هو الأوضح. فمصنف أب يشير إلى اثني عشر ملفًا شهريًا؛ سجّل الاثني عشر جميعًا، وأعِد الحساب مرة واحدة، واقرأ الأرقام الموحَّدة دون فتح Excel إطلاقًا. ويجب أن يطابق اسم التسجيل لكل ملف ما تقوله صيغ الأب فعليًا، وهذا يستحق التحقق منه مقابل نص الصيغة بدلاً من افتراض تطابقه مع اسم الملف
وتحليل السيناريوهات هو الثاني. سجّل مصدرًا، واكتب مجموعة من الافتراضات فيه، وأعِد حساب النموذج التابع، وسجّل المخرجات، ثم كرّر. ولأن المصدر كائن حي، لا يُكتب أي ملف بين التكرارات، وتكلّف مئة سيناريو مئة عملية إعادة حساب بدلاً من مئة دورة حفظ وإعادة تحميل
والتحقق قبل التسليم هو الثالث والأقل وضوحًا. افتح مصنفًا، وسجّل مرافقيه، وأعِد الحساب، وقارن النتائج بالقيم التي كان يحملها الملف بالفعل. وعدم التطابق يعني أن القيم المخزَّنة مؤقتًا قديمة، وهذا عيب يستحق اكتشافه قبل أن يتلقى عميل الملف. وتلك المقارنة رفيقة طبيعية لمقارنة المصنفات الموصوفة في مقارنة مصنفي Excel
نظافة المراجع قبل أن تعتمد عليها
شغّل تمريرة تحليل صيغ أولاً. فهي تُبلِّغ عن الدوال المفقودة، والمراجع الخارجية، ومكوّنات الاعتمادية الدائرية في اجتياز واحد، وهذا يخبرك بالضبط بأسماء الكتب التي يتوقعها مستند قبل أن تبحث عن الملفات:
var
Issues: TArray<TXLSXFormulaIssue>;
I: Integer;
begin
Issues := Main.AnalyzeFormulaIssues;
for I := 0 to High(Issues) do
if Issues[I].Kind = xlsxFormulaIssueExternalReference then
Writeln(Format('sheet %d R%dC%d needs [%s] (%s)',
[Issues[I].Sheet, Issues[I].Row, Issues[I].Col,
Issues[I].ExternalWorkbook, Issues[I].SourceFileName]));
end;
وعادتان أخريان توفّران الوقت. حافظ على اسم التسجيل قياسيًا — سجّل باسم الملف العادي واترك عملية التطبيع تتولى الصيغ المُقتبَسة والمُسبَقة بمسار في الصيغ. وعامل مصنفًا يشير إلى ملفات لا يمكنك توفيرها كأثر للقراءة فقط: فإعادة حسابه ستحافظ على القيم المخزَّنة مؤقتًا، لكن أي تحرير يغيّر خلية تابعة يترك المستند في حالة تكون فيها بعض القيم حديثة وبعضها تاريخيًا، دون أي شيء في الملف يقول أيها كذلك. ونسخ الصيغ بين المصنفات عملية مختلفة لها قواعد إعادة ربط خاصة بها، موضحة في النسخ عبر المصنفات وإعادة ربط الصيغ، وتضيف الأسماء المُعرَّفة طبقة أخرى موضحة في الأسماء المُعرَّفة والصيغ عبر الأوراق
يعمل التقييم الحي عبر المصنفات، وإعادة الحساب التزايدية، وتحليل الصيغ، على المحرك نفسه لـ Delphi و C++Builder؛ وتجد قائمة الميزات الكاملة على صفحة مكوّن HotXLS لجداول البيانات في Delphi