Technical Article

Izdvajanje informacija o sažetku dokumenta iz Excel datoteka u Delphiju

Kada obrađujete velike serije Excel tabela u automatizovanom cevovodu, retko želite da učitate ceo dokument u memoriju samo da biste shvatili o čemu se radi. Često su metapodaci ugrađeni u datoteku, kao što su autor, naslov, datum kreiranja i prilagođena svojstva, dovoljni za usmeravanje, indeksiranje ili odbacivanje dokumenta. U svetu Microsoft Office-a, ovi metapodaci su poznati kao informacije o sažetku dokumenta.

Izdvajanje ovih informacija nativno u Delphiju bez oslanjanja na OLE automatizaciju (što zahteva da Excel bude instaliran na host mašini) zahteva direktno parsiranje osnovne strukture datoteke. U ovom članku ćemo pogledati kako funkcionišu sažeci dokumenata u Excel datotekama i kako da ih efikasno izdvojite koristeći sirovo parsiranje tokova.

Razumevanje tokova metapodataka u Excelu

Istorijski gledano, starije Excel datoteke (.xls) se čuvaju u OLE Compound Document formatima, efektivno delujući kao mini sistemi datoteka koji sadrže tokove i skladišta. Metapodaci se nalaze u dva specifična toka:

  • SummaryInformation: Sadrži standardna svojstva kao što su naslov, predmet, autor, ključne reči i broj revizije.
  • DocumentSummaryInformation: Sadrži proširena svojstva kao što su kompanija, menadžer i korisnički definisana svojstva.

Moderne Excel datoteke (.xlsx) koriste Office Open XML (OOXML) format, koji predstavlja zipovanu XML strukturu. Metapodaci se ovde nalaze u docProps/core.xml, docProps/app.xml i docProps/custom.xml. Robusna Delphi komponenta za parsiranje mora besprekorno da obrađuje obe interne strukture, dok istovremeno programeru nudi jedinstveni API.

Parsiranje OLE složenih dokumenata u Delphiju

Da biste pročitali SummaryInformation iz stare .xls datoteke bez alata trećih strana, morate parsirati OLE strukturisano skladište. Microsoft to izlaže kroz COM interfejs IPropertySetStorage. Evo sirove Delphi implementacije koja izbegava pokretanje Excela:

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;

Programsko izdvajanje sa HotXLS-om

Iako Windows COM API radi za .xls datoteke, on ne radi za moderne .xlsx datoteke (koje su ZIP arhive). Pored toga, korišćenje COM API-ja na različitim platformama (npr. na Linuxu ili macOS-u preko FireMonkey-a) je nemoguće. Nedavna ažuriranja HotXLS komponente uvela su namenske jedinice (npr. lxXlsSummary) da izoluju i optimizuju čitanje ovih tokova sažetaka kroz oba formata potpuno nativno u Delphi kodu.

Primer za više platformi

Koristeći interfejse XlsReadDocumentSummaryInformation i XlsReadSummaryInformation, možete brzo da preuzmete nizove metapodataka iz .xls i .xlsx bez brige o arhitekturi osnovnog sistema datoteka.

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;

Zašto je namensko izdvajanje sažetaka važno

Glavna prednost ovog pristupa su performanse i bezbednost memorije. Izbegavanjem instanciranja punog DOM-a (Document Object Model) radne sveske i parsiranjem samo docProps/core.xml ili OLE tokova svojstava, otisak vaše aplikacije ostaje neverovatno mali. Ako indeksirate 10.000 Excel datoteka preko mrežnog diska, pokušaj potpunog parsiranja svake datoteke će zagušiti vašu memoriju i potrajati satima. Namensko izdvajanje sažetaka završava isti zadatak za nekoliko sekundi.

Štaviše, nativno čitanje tokova osigurava da vaša aplikacija može da se pokreće kao pozadinski servis ili na Linux serveru bez korisničkog interfejsa (headless) a da nikada ne pozove Excel.exe, što je kritičan zahtev za moderne skalabilne arhitekture.

Napomena: Sveobuhvatno parsiranje Excela i alati za izdvajanje metapodataka dostupni su u HotXLS VCL komponenti.