Technical Article

Postavljanje svojstava Excel dokumenta i metapodataka radne knjige u Delphiju uz HotXLS

Tablični dokument nosi dva sloja identiteta. Postoji mreža ćelija i postoje metapodaci dokumenta koji idu uz nju: naslov, autor, tvrtka, ključne riječi, vremenske oznake. Excel nikada ne prikazuje taj drugi sloj u mreži, no to je sloj koji Windows Search indeksira, koji SharePoint čita za naslov dokumenta i prema kojem sustav za upravljanje zapisima arhivira datoteke. Kada generirana radna knjiga naslijedi svog Autora i Naslov iz predloška na temelju kojeg je izgrađena, svaki nizvodni sustav bilježi dizajnera predloška kao autora četiri tisuće korisničkih izvadaka. Metapodaci nisu nigdje točni, a svugdje se konzultiraju.

HotXLS prikazuje ovaj sloj kao obična svojstva na razini radne knjige na oba svoja mehanizma: BIFF sučelje za .xls i OOXML sučelje za .xlsx. Čitate polje nakon otvaranja datoteke i pišete polje prije spremanja. Knjižnica odlučuje u koji fizički spremnik vrijednost slijeće. Ono što je vrijedno razumjeti prije nego što napišete generator jest koja polja pojedini format zapravo podržava, gdje ta polja fizički žive i jedno glavno pravilo koje upravlja time bilježi li .xlsx uopće metapodatke.

Dva formata, dva modela pohrane

Razlog zašto knjižnica za tablične dokumente treba dvije implementacije metapodataka, i razlog zašto napola dovršeni alati ispravno označavaju jedan format, a zaboravljaju drugi, jest taj što .xls i .xlsx drže svoja svojstva na nepovezanim mjestima. BIFF radna knjiga ih zapisuje u OLE tokove složenih datoteka (compound-file), uglavnom skup svojstava SummaryInformation koji je stariji od samog Excela, zajedno sa zapisom WRITEACCESS unutar toka koji imenuje onoga tko je zadnji spremio datoteku. OOXML radna knjiga ih drži kao XML dijelove unutar zip paketa, podijeljene prema namjeni: docProps/core.xml drži polja Dublin Core (naslov, autor, predmet, ključne riječi, datumi), a docProps/app.xml drži polja na razini aplikacije kao što su tvrtka i generirana aplikacija, prema ECMA-376 Part 1.

HotXLS objedinjuje oba ova modela pohrane u izravna svojstva objekta radne knjige. Nikada ne otvarate tok skupa svojstava niti ručno uređujete XML dio. Radnoj knjizi dodjeljujete nizove znakova i datume, a ispravan se spremnik materijalizira za onaj format u kojem spremate.

Označavanje generiranih radnih knjiga iz poslovnog zapisa

Na strani XLSX-a, TXLSXWorkbook izlaže Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application i AppVersion kao nizove znakova, uz Created i Modified kao vrijednosti TDateTime gdje nula znači da polje nije postavljeno. Pravilo koje zatvara problem nasljeđivanja stane u jednu rečenicu: dodijelite svako polje pri svakom pokretanju, uzimajući vrijednosti iz poslovnog zapisa umjesto da vjerujete onome što je predložak slučajno nosio.

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('statement-template.xlsx') <> 1 then
      raise Exception.Create('Template not available');

    // Overwrite every field: anything left untouched is
    // inherited from whoever designed the template.
    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;

Polje Keywords (ključne riječi) zaslužuje više pažnje nego što mu se obično pridaje. Tražilice ga indeksiraju doslovno, kako Windows Search, tako i SharePoint i većina DMS proizvoda, pa konvencija odvajanja točka-zarezom koja nosi broj računa i razdoblje pretvara svaku isporučenu radnu knjigu u zapis koji se može pronaći bez upita prema bazi podataka. Taj isti doseg ujedno je i kvaka. Svojstva putuju sa svakom kopijom datoteke, daleko izvan kontrola pristupa sustava koji ih je napisao, pa osobnim podacima tamo nije mjesto.

Par vremenskih oznaka nosi semantiku koju je bolje utvrditi pravilima nego prepustiti navici. Created bi trebao označavati trenutak kada je vaš cjevovod generirao dokument i nakon toga ostati zamrznut. Modified je polje koje Excel ažurira kad god primatelj spremi datoteku, pa je razlika između ta dva podatka nakon isporuke jasan dokaz da je netko naknadno uređivao radnu knjigu, što rješava mnoge sporove o tome čije brojke proslijeđena tablica zapravo sadrži. Jedna se zamka krije u nepostavljenom stanju: to je doslovna vrijednost nula, a ne iznimka ili null, pa revizijski kod mora izričito provjeriti nulu. Oblikujte nepostavljeni TDateTime bez te zaštite i vaši će se dnevnici napuniti pogrešnim datumom iz prosinca 1899. godine.

DocPropsTouched: radna knjiga koja se isporučuje bez docProps

Zastavica samo za čitanje, DocPropsTouched, upravlja pisanjem XLSX svojstava. Radna knjiga u kojoj nijedno svojstvo nikada nije dodijeljeno ne proizvodi nikakve docProps dijelove; HotXLS odbija pisati prazan kostur metapodataka. Ponašanje je uredno i ima dvije posljedice koje vrijedi uzeti u obzir pri dizajnu.

Ulazni kod na strani konzumenta ne smije pretpostavljati da core.xml postoji u svakom paketu. Alat koji ga strogo zahtijeva odbacit će savršeno valjane minimalne datoteke. A ako vaša pravila usklađenosti zahtijevaju da svaki odlazni dokument nosi barem identitet generatora, taj zahtjev postaje kod, a ne svojstvo formata: bezuvjetno dodijelite Application i Author u stazi spremanja, budući da je nedirnuta radna knjiga potpuno legalna prema specifikaciji, iako tiho krši vaša pravila.

Naslijeđeno sučelje XLS i zamka Comments

BIFF sučelje nosi stariji, manji skup polja: Title, Subject, Author, Keywords, Comments, Company i Manager, plus LastSavedBy, alias za UserName, koji piše zapis WRITEACCESS koji Excel prikazuje kada drugi korisnik zaključa datoteku.

var
  Writer, Reader: IXLSWorkbook;   // reference-counted interface: no manual Free
begin
  Writer := TXLSWorkbook.Create;
  Writer.Sheets.Add.Cells.Item[1, 1].Value := 'Confidential';
  Writer.EncryptionPassword := 'S3cret!';
  Writer.SaveAs('confidential.xls');

  Reader := TXLSWorkbook.Create;
  if Reader.Open('confidential.xls', 'S3cret!') > 0 then
    Writeln(Reader.Sheets[1].Cells.Item[1, 1].Value);  // Entries are 1-based
end;

Jedan sukob naziva uzrokuje česte zabune. Svojstvo Comments na razini dokumenta ovdje je slobodni tekst prikazan u dijaloškom okviru svojstava datoteke. Ono nema nikakve veze s komentarima ćelija, koji su objekti sloja crtanja pričvršćeni na raspone kroz potpuno zaseban API. Pregled koda koji prihvaća 'već pišemo Comments' bez provjere na što se točno odnosi, prihvatio je tvrdnju o pogrešnoj značajki, a to se događa češće nego što bi zajednički naziv sugerirao. Dijele nekoliko slova i niti jedan bajt pohrane.

Čitanje metapodataka pri unosu i nedostatak sonde

Čitanje je simetrično. Nakon Open, ista se svojstva vraćaju popunjena iz datoteke, što pretvara reviziju metapodataka dolaznih radnih knjiga u kratku petlju.

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;

Planirajte oko jednog ograničenja dok to radite. Ne postoji sonda samo za svojstva. GetSheetNames može izlistati listove bez učitavanja radne knjige, ali čitanje svojstava Title ili Author zahtijeva potpuni Open, tako da trijaža metapodataka u velikoj arhivi plaća punu cijenu analize za svaku datoteku. Na strani BIFF-a možete smanjiti taj trošak za revizije samo za čitanje postavljanjem _DisableGraphics na true prije otvaranja, što u potpunosti preskače sloj crtanja. To odgovara petlji koja čita samo svojstva i statistiku ćelija, ali je potpuno pogrešno u trenutku kada bi ta ista instanca mogla spremati, jer bi se preskočeni sadržaj crteža odbacio. Kada sama struktura lista može unaprijed filtrirati skup (pri čemu su izvozi s jednim listom očigledna stvar za preskakanje), brze tehnike u našem članku o popisu listova i laganoj inspekciji smanjuju broj datoteka koje stižu do spremnika. A na poslovima skupnog označavanja, gdje se ispisuju tisuće izlaza umjesto da se pregledavaju, obrasci propusnosti na strani pisanja iz našeg članka o strujnom pisanju za skupne poslove prenose se bez promjena, budući da dodjela svojstava ne dodaje mjerljivo vrijeme spremanja.

Prelazak formata i suzbijanje curenja podataka

Svojstva prolaze čisto unutar jednog sučelja: otvorite .xlsx, uredite ga, spremite i skup se vraća netaknut. Prelazak između formata je mjesto gdje pretpostavka pariteta puca, jer se skupovi polja BIFF i OOXML ne podudaraju jedan prema jedan. BIFF ima Manager i nema vremenskih oznaka; OOXML ima Category, Description i par Created/Modified. Pretvarač koji slijepo kopira gubi ono što odredišni format ne može zadržati, stoga eksplicitno mapirajte polja i stavite to mapiranje na svoju kontrolnu listu pretvorbe uz sve ostalo što ne preživljava putovanje.

Curenje koje otvara nasljeđivanje predloška ide u drugom smjeru: informacije koje nikada niste namjeravali poslati van. Imena autora, interne oznake projekata parkirane u ključnim riječima, nacrt naslova koji nitko nije odobrio. Disciplina prepisivanja svega iz gornjeg generatora je jedina obrana, a vrijedi je provjeriti onako kako bi to učinio netko izvana: otvaranjem dijaloškog okvira Properties koji svaki kupac može dohvatiti ili raspakiravanjem .xlsx datoteke i čitanjem docProps/core.xml izravno iz paketa. Ono što tamo vidite je upravo ono što vidi svaki nizvodni indeksator.

Ta nizvodna vidljivost također je razlog zašto nekoliko polja zaslužuje više pažnje od ostalih. Title (Naslov), Author (Autor), Keywords (Ključne riječi, koje se pojavljuju kao oznake/tags) i Comments ili Description nose većinu težine indeksiranja u SharePointu i Windows Searchu. Naslov koji je uistinu jedinstven po dokumentu, a koji sadrži razdoblje i račun, čini više za mogućnost pronalaženja nego bilo koja shema imenovanja mapa postavljena na to, a košta samo jednu dodjelu po spremanju.

Svojstva dokumenta najjeftinije su profesionalno poliranje koje generirana radna knjiga može nositi i najčešći isporučeni nedostatak kada nitko ne vodi računa o njima. Obje površine svojstava opisane ovdje pripadaju komponenti HotXLS, koja ih piše izvorno za XLS i XLSX bez automatizacije Excela.