Sešit nese dvě vrstvy identity. Je tu mřížka buněk, a je tu dokumentová metadata, která jedou vedle ní: název, autor, společnost, klíčová slova, časová razítka. Excel tuto druhou vrstvu v mřížce nikdy nezobrazí, přesto je to vrstva, kterou indexuje Windows Search, kterou SharePoint čte, aby dokument pojmenoval, a podle které dokument zařadí systém pro správu záznamů. Když vygenerovaný workbook zdědí svého Author a Title ze šablony, ze které vznikl, každý navazující systém zaznamená jako autora čtyř tisíc zákaznických výpisů designéra šablony. Metadata nejsou správná nikde a přesto se s nimi konzultuje všude
HotXLS zpřístupňuje tuto vrstvu jako obyčejné vlastnosti na úrovni workbooku v obou svých enginech: fasáda BIFF pro .xls a fasáda OOXML pro .xlsx. Pole čtete po otevření souboru a zapisujete ho před jeho uložením. O tom, do jakého fyzického kontejneru hodnota dopadne, rozhoduje knihovna. Než napíšete generátor, stojí za to pochopit, která pole každý formát skutečně podporuje, kde ta pole fyzicky žijí, a jedno pravidlo, které rozhoduje, zda .xlsx vůbec zaznamená nějaká metadata
Dva formáty, dva modely úložiště
Důvod, proč knihovna pro tabulkové procesory potřebuje dvě implementace metadat, a důvod, proč napůl dokončené nástroje jeden formát otisknou správně a na druhý zapomenou, je ten, že .xls a .xlsx drží své vlastnosti na zcela nesouvisejících místech. Workbook BIFF je zapisuje do streamů typu OLE compound-file, především do sady vlastností SummaryInformation, která existovala dřív než samotný Excel, spolu se streamovým záznamem WRITEACCESS, jenž pojmenovává toho, kdo soubor uložil naposledy. Workbook OOXML je drží jako části XML uvnitř zip balíčku, rozdělené podle účelu: docProps/core.xml nese pole Dublin Core (název, tvůrce, předmět, klíčová slova, data) a docProps/app.xml nese pole na úrovni aplikace, jako je společnost a generující aplikace, podle ECMA-376 Part 1
HotXLS oba tyto modely úložiště zplošťuje do přímých vlastností objektu workbooku. Nikdy sami neotevíráte stream sady vlastností ani ručně needitujete část XML. Workbooku přiřazujete řetězce a data, a správný kontejner se sám zhmotní podle toho, do jakého formátu ukládáte
Otisknutí vygenerovaných workbooků podle obchodního záznamu
Na straně XLSX vystavuje TXLSXWorkbook jako řetězce Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application a AppVersion, plus Created a Modified jako hodnoty TDateTime, kde nula znamená nenastaveno. Pravidlo, které uzavírá díru způsobenou dědičností, se dá shrnout jednou větou: při každém běhu přiřaďte každé pole, přičemž hodnoty berte z obchodního záznamu, ne z důvěry v to, co náhodou nesla šablona
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open('statement-template.xlsx') <> 1 then
raise Exception.Create('Template not available');
// Přepište každé pole: cokoli zůstane nedotčené, je
// zděděno po tom, kdo šablonu navrhl.
Book.Title := 'Account Statement 2026-06 / ACME Corp';
Book.Subject := 'Monthly account statement';
Book.Author := 'Billing Service 4.2';
Book.LastModifiedBy := 'Billing Service 4.2';
Book.Company := 'Northwind Financial';
Book.Category := 'Customer Delivery';
Book.Keywords := 'statement;billing;2026-06;acct-10024';
Book.Description := 'Generated document - manual edits are not retained';
Book.Created := Now;
Book.Modified := Now;
Book.SaveAs('statement-10024.xlsx');
finally
Book.Free;
end;
end;
Pole Keywords si zaslouží víc pozornosti, než obvykle dostává. Vyhledávací infrastruktura ho indexuje doslova, Windows Search, SharePoint i většina produktů DMS stejně, takže konvence oddělená středníky nesoucí číslo účtu a období promění každý doručený workbook v dohledatelný záznam bez jediné cesty do databáze. Stejný dosah je zároveň háček. Vlastnosti cestují s každou kopií souboru, daleko za hranicemi řízení přístupu systému, který je zapsal, takže osobní údaje sem nepatří
Tato dvojice časových razítek nese sémantiku, kterou se vyplatí zakotvit v politice, ne nechat na zvyku. Created by mělo označit okamžik, kdy váš pipeline dokument vygeneroval, a poté zůstat zamrzlé. Modified je pole, které Excel aktualizuje pokaždé, když příjemce soubor uloží, takže rozchod mezi oběma hodnotami po doručení je přímý důkaz, že někdo workbook po cestě upravil, což vyřeší nejeden spor o to, čí čísla přeposlaná tabulka vlastně nese. Jedna past se skrývá ve stavu nenastaveno: je to doslovná hodnota nula, ne výjimka a ne null, takže auditní kód musí na nulu testovat explicitně. Naformátujte nenastavené TDateTime bez této pojistky a vaše logy se zaplní sebejistě špatným datem z prosince 1899
DocPropsTouched: workbook, který se odešle bez docProps
Příznak jen pro čtení, DocPropsTouched, řídí zapisovač vlastností XLSX. Workbook, ve kterém nebyla přiřazena žádná vlastnost, nevyprodukuje vůbec žádné části docProps; HotXLS odmítá zapsat prázdnou kostru metadat. Toto chování je úhledné a má dva důsledky, se kterými se vyplatí počítat při návrhu
Vstupní kód na přijímací straně nesmí předpokládat, že core.xml existuje v každém balíčku. Nástroj, který ho tvrdě vyžaduje, odmítne naprosto platné minimální soubory. A pokud vaše compliance vyžaduje, aby každý odchozí dokument nesl přinejmenším identitu generátoru, ten požadavek se musí stát kódem, ne vlastností formátu: přiřaďte Application a Author v ukládací cestě bezpodmínečně, protože nedotčený workbook je podle specifikace zcela legální, zatímco potichu porušuje vaši politiku
Starší rozhraní XLS a past jménem Comments
Fasáda BIFF nese starší, menší sadu polí: Title, Subject, Author, Keywords, Comments, Company a Manager, plus LastSavedBy, alias UserName, který zapisuje záznam WRITEACCESS, jenž Excel zobrazí, když má soubor uzamčený jiný uživatel
var
Legacy: IXLSWorkbook; // referenčně počítané rozhraní: bez ručního Free
begin
Legacy := TXLSWorkbook.Create;
if Legacy.Open('archive-1999.xls') <= 0 then
raise Exception.Create('Cannot open archive file');
Legacy.Title := 'FY1999 ledger (migrated copy)';
Legacy.Author := 'Archive Migration Batch';
Legacy.Company := 'Northwind Financial';
Legacy.Comments := 'Migrated 2026-06-11; source retained in cold storage';
Legacy.LastSavedBy := 'migration-svc'; // záznam BIFF WRITEACCESS
Legacy.SaveAs('archive-1999-stamped.xls');
end;
Jedna kolize v pojmenování způsobuje opakující se zmatky. Vlastnost Comments na úrovni dokumentu je zde volný textový poznámkový text zobrazený v dialogu vlastností souboru. Nemá nic společného s komentáři buněk, což jsou objekty kresební vrstvy připojené k rozsahům přes zcela oddělené API. Code review, které přijme tvrzení „už Comments zapisujeme" bez ověření, které z nich se míní, přijalo tvrzení o špatné funkci, a to se stává častěji, než by sdílený název naznačoval. Obě mají společná čtyři písmena a ani jeden bajt úložiště
Čtení metadat při vstupu a mezera v sondování
Čtení je symetrické. Po Open se stejné vlastnosti vrátí naplněné ze souboru, což mění audit metadat příchozích workbooků na krátkou smyčku
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.Open(FileName) = 1 then
begin
Writeln(Format('%s | title="%s" author="%s" created=%s',
[ExtractFileName(FileName), Book.Title, Book.Author,
FormatDateTime('yyyy-mm-dd', Book.Created)]));
if Book.Created = 0 then
Writeln(' no creation date recorded');
end;
finally
Book.Free;
end;
end;
S jedním omezením přitom počítejte při plánování. Neexistuje sonda jen pro vlastnosti. GetSheetNames dokáže vypsat listy bez načtení celého workbooku, ale přečtení Title nebo Author znamená plné Open, takže třídění metadat napříč velkým archivem zaplatí plnou cenu parsování za každý soubor. Na straně BIFF můžete tuto cenu u auditů jen pro čtení zkrátit nastavením _DisableGraphics na true před otevřením, což rovnou přeskočí kresební vrstvu. Hodí se to do smyčky, která čte jen vlastnosti a statistiky buněk, a je to přesně špatně ve chvíli, kdy by tatáž instance mohla ukládat, protože vynechaný kresební obsah by se ztratil. Když struktura listů sama o sobě umí předfiltrovat množinu, exporty s jedním listem jsou zjevná věc k vynechání, levné techniky v našem článku o výpisu listů a lehké inspekci sníží počet souborů, které se dostanou do drahého průchodu. A u hromadných otiskovacích úloh, kde se tisíce výstupů zapisují, ne inspektují, se vzory propustnosti na straně zápisu z našeho článku o streamovaném zápisu pro dávkové úlohy přenášejí beze změny, protože přiřazení vlastností nepřidá k času ukládání nic měřitelného
Přechod mezi formáty a zamezení úniku
Vlastnosti proběhnou round-tripem čistě uvnitř jedné fasády: otevřete .xlsx, upravíte ho, uložíte, a sada se vrátí neporušená. Přechod mezi formáty je místo, kde se předpoklad parity rozpadá, protože sady polí BIFF a OOXML se neshodují jedna k jedné. BIFF má Manager a žádná časová razítka; OOXML má Category, Description a dvojici Created/Modified. Konvertor, který kopíruje naslepo, ztratí vše, co cílový formát neumí pojmout, takže pole mapujte explicitně a mapování si dejte do kontrolního seznamu konverze hned vedle všeho ostatního, co cestu nepřežije
Únik, který otevírá dědičnost ze šablony, míří opačným směrem: informace, které jste nikdy neměli v úmyslu poslat ven. Jména autorů, interní označení projektů zaparkovaná v klíčových slovech, název konceptu, který nikdo neschválil. Disciplína „přepiš úplně vše" z generátoru výše je celou obranou, a vyplatí se ji ověřit stejně, jako by to udělal někdo zvenčí: otevřením dialogu vlastností, ke kterému se dostane každý zákazník, nebo rozbalením .xlsx a přečtením docProps/core.xml přímo z balíčku. To, co tam uvidíte, je přesně to, co vidí každý navazující indexer
Právě tato viditelnost po proudu je i důvodem, proč si pár polí zaslouží víc péče než ostatní. Title, Author, Keywords (které se navenek zobrazují jako Tags) a Comments nebo Description nesou v SharePointu a Windows Search většinu indexační váhy. Title, který je pro každý dokument opravdu jedinečný a nese v sobě období a účet, udělá pro dohledatelnost víc než jakékoli schéma pojmenování složek navrstvené nahoře, a stojí jedno přiřazení za každé uložení
Dokumentové vlastnosti jsou nejlevnější profesionální lesk, který vygenerovaný workbook může nést, a zároveň nejčastěji doručovaná vada ve chvíli, kdy je nikdo nevlastní. Obě zde popsaná rozhraní vlastností patří ke HotXLS Delphi Component, který je nativně zapisuje pro XLS i XLSX bez automatizace Excelu