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.