Technical Article

استخراج معلومات ملخص المستند من ملفات Excel في Delphi

عند معالجة دفعات كبيرة من جداول بيانات Excel في مسار آلي، نادرًا ما ترغب في تحميل المستند بأكمله في الذاكرة فقط لمعرفة ماهيته. في كثير من الأحيان، تكون البيانات الوصفية المضمنة داخل الملف، مثل المؤلف، والعنوان، وتاريخ الإنشاء، والخصائص المخصصة، كافية لتوجيه المستند أو فهرسته أو رفضه. في عالم Microsoft Office، تُعرف هذه البيانات الوصفية باسم معلومات ملخص المستند (Document Summary Information).

يتطلب استخراج هذه المعلومات محليًا في Delphi دون الاعتماد على أتمتة OLE (والتي تتطلب تثبيت Excel على الجهاز المضيف) تحليل بنية الملف الأساسية مباشرة. في هذه المقالة، سنلقي نظرة على كيفية عمل ملخصات المستندات في ملفات Excel وكيفية استخراجها بكفاءة باستخدام تحليل الدفق الخام (raw stream parsing).

فهم تيارات البيانات الوصفية في Excel

تاريخيًا، يتم تخزين ملفات Excel القديمة (.xls) بتنسيقات OLE Compound Document، والتي تعمل فعليًا كأنظمة ملفات مصغرة تحتوي على تيارات ومخازن. توجد البيانات الوصفية في تيارين محددين:

  • SummaryInformation: يحتوي على الخصائص القياسية مثل العنوان والموضوع والمؤلف والكلمات الرئيسية ورقم المراجعة.
  • DocumentSummaryInformation: يحتوي على خصائص موسعة مثل الشركة والمدير والخصائص المخصصة المعرفة من قبل المستخدم.

تستخدم ملفات Excel الحديثة (.xlsx) تنسيق Office Open XML (OOXML)، وهو عبارة عن بنية XML مضغوطة. توجد البيانات الوصفية هنا في docProps/core.xml و docProps/app.xml و docProps/custom.xml. يجب أن يتعامل مكون التحليل القوي في Delphi بسلاسة مع كل من البنيتين الداخليتين مع كشف واجهة برمجة تطبيقات موحدة للمطور.

تحليل مستندات OLE المركبة في Delphi

لقراءة SummaryInformation من ملف `.xls` قديم بدون أدوات خارجية، تحتاج إلى تحليل OLE Structured Storage. تكشف Microsoft عن هذا من خلال واجهة COM IPropertySetStorage. إليك تطبيق Delphi خام يتجنب تشغيل Excel:

uses
  System.SysUtils, System.Win.ComObj, Winapi.ActiveX, Winapi.Windows;

procedure ExtractXlsSummaryInfo(const FileName: string);
var
  Stg: IStorage;
  PropSetStg: IPropertySetStorage;
  PropStg: IPropertyStorage;
  PropSpec: TPropSpec;
  PropVariant: TPropVariant;
  Hr: HRESULT;
begin
  // Open the OLE Compound Document
  Hr := StgOpenStorage(PWideChar(WideString(FileName)), nil,
    STGM_READ or STGM_SHARE_DENY_WRITE, nil, 0, Stg);
    
  if Failed(Hr) then
    raise Exception.Create('Failed to open OLE storage. File may not be a valid .xls document.');

  // Query for the property set storage interface
  if Stg.QueryInterface(IPropertySetStorage, PropSetStg) = S_OK then
  begin
    // Open the SummaryInformation stream (FMTID_SummaryInformation)
    Hr := PropSetStg.Open(FMTID_SummaryInformation, STGM_READ or STGM_SHARE_EXCLUSIVE, PropStg);
    if Succeeded(Hr) then
    begin
      // Read the Author property (PIDSI_AUTHOR = 4)
      PropSpec.ulKind := PRSPEC_PROPID;
      PropSpec.propid := PIDSI_AUTHOR;
      
      if PropStg.ReadMultiple(1, @PropSpec, @PropVariant) = S_OK then
      begin
        if PropVariant.vt = VT_LPSTR then
          Writeln('Author: ', string(AnsiString(PropVariant.pszVal)));
        PropVariantClear(PropVariant);
      end;
    end;
  end;
end;

الاستخراج البرمجي باستخدام HotXLS

بينما تعمل واجهة برمجة تطبيقات Windows COM مع ملفات `.xls`، فإنها لا تعمل مع ملفات `.xlsx` الحديثة (وهي أرشيفات ZIP). علاوة على ذلك، يعد استخدام واجهة برمجة تطبيقات COM عبر الأنظمة الأساسية (على سبيل المثال، على Linux أو macOS عبر FireMonkey) أمرًا مستحيلًا. قدمت التحديثات الأخيرة لمكون HotXLS وحدات مخصصة (مثل lxXlsSummary) لعزل وتحسين قراءة تيارات الملخص هذه عبر كلا التنسيقين بشكل محلي تمامًا في كود Delphi.

مثال عبر الأنظمة الأساسية

باستخدام واجهتي XlsReadDocumentSummaryInformation و XlsReadSummaryInformation، يمكنك بسرعة الحصول على سلاسل البيانات الوصفية من كل من `.xls` و `.xlsx` دون القلق بشأن بنية نظام الملفات الأساسية.

uses
  lxXlsSummary;

var
  Summary: TXlsSummaryInfo;
  ExtendedInfo: TXlsDocumentSummaryInfo;
begin
  // Extract standard summary from an OOXML format seamlessly
  Summary := XlsReadSummaryInformation('C:\Data\FinancialReport.xlsx');
  try
    Writeln('Title: ', Summary.Title);
    Writeln('Author: ', Summary.Author);
    Writeln('Creation Date: ', DateTimeToStr(Summary.CreateTime));
  finally
    Summary.Free;
  end;

  // Extract extended document summary
  ExtendedInfo := XlsReadDocumentSummaryInformation('C:\Data\FinancialReport.xlsx');
  try
    Writeln('Company: ', ExtendedInfo.Company);
    Writeln('Manager: ', ExtendedInfo.Manager);
  finally
    ExtendedInfo.Free;
  end;
end;

لماذا يهم استخراج الملخص المخصص

الفائدة الأساسية من هذا النهج هي الأداء وأمان الذاكرة. من خلال تجنب إنشاء نموذج كائن المستند (DOM) الكامل للمصنف، وتحليل docProps/core.xml أو تيارات خصائص OLE فقط، تظل بصمة تطبيقك صغيرة بشكل لا يصدق. إذا كنت تقوم بفهرسة 10,000 ملف Excel عبر مشاركة شبكة، فإن محاولة تحليل كل منها بالكامل ستؤدي إلى إرهاق ذاكرتك وتستغرق ساعات. يكمل استخراج الملخص المخصص نفس المهمة في ثوانٍ.

علاوة على ذلك، تضمن قراءة التيارات محليًا أن تطبيقك يمكن تشغيله كخدمة خلفية أو على خادم Linux مقطوع الرأس (headless) دون استدعاء Excel.exe أبدًا، وهو متطلب حاسم للبنى الحديثة القابلة للتطوير.

ملاحظة: تتوفر أدوات شاملة لتحليل Excel واستخراج البيانات الوصفية في مكون HotXLS VCL.