Tekninen artikkeli

Excel-dokumentin ominaisuuksien ja metatietojen asettaminen Delphissä HotXLS:llä

Laskentataulukolla on kaksi identiteettikerrosta. Ensimmäinen on soluruudukko ja toinen sen mukana kulkevat asiakirjan metatiedot: otsikko, tekijä, yritys, avainsanat ja aikaleimat. Excel ei koskaan näytä tätä toista kerrosta ruudukossa, mutta Windows Search indeksoi sen, SharePoint lukee sen asiakirjan otsikointiin ja asiakirjahallintajärjestelmä arkistoi sen perusteella. Kun tuotettu työkirja perii Author- ja Title-arvonsa pohjasta, josta se rakennettiin, jokainen jatkojärjestelmä kirjaa pohjan suunnittelijan neljäntuhannen asiakastiliotteen tekijäksi. Metatiedot ovat väärin kaikkialla ja niitä käytetään kaikkialla

HotXLS tuo tämän kerroksen esiin tavallisina työkirjatason ominaisuuksina molemmissa moottoreissaan: BIFF-julkisivussa .xls-muodolle ja OOXML-julkisivussa .xlsx-muodolle. Luet kentän tiedoston avaamisen jälkeen ja kirjoitat kentän ennen tiedoston tallentamista. Kirjasto päättää, mihin fyysiseen säiliöön arvo päätyy. Ennen generaattorin kirjoittamista kannattaa ymmärtää, mitä kenttiä kumpikin muoto todella tukee, missä nämä kentät fyysisesti sijaitsevat ja mikä yksittäinen porttisääntö määrää, tallentaako .xlsx lainkaan metatietoja

Kaksi muotoa, kaksi tallennusmallia

Syy siihen, että laskentataulukkokirjasto tarvitsee kaksi metatietototeutusta ja että puolivalmiit työkalut leimaavat yhden muodon oikein ja unohtavat toisen, on se, että .xls ja .xlsx säilyttävät ominaisuutensa toisiinsa liittymättömissä paikoissa. BIFF-työkirja kirjoittaa ne OLE-yhdistelmätiedoston virtoihin, pääasiassa itse Exceliä edeltävään SummaryInformation-ominaisuusjoukkoon sekä tiedoston viimeksi tallentaneen henkilön nimeävään virran sisäiseen WRITEACCESS-tietueeseen. OOXML-työkirja säilyttää ne XML-osina zip-paketissa tarkoituksen mukaan jaettuina: docProps/core.xml sisältää Dublin Core -kentät (otsikon, luojan, aiheen, avainsanat ja päivämäärät) ja docProps/app.xml sovellustason kentät, kuten yrityksen ja luovan sovelluksen, ECMA-376 Part 1 -määrityksen mukaisesti

HotXLS tasoittaa molemmat tallennusmallit työkirjaolion suoriksi ominaisuuksiksi. Sinun ei tarvitse koskaan avata ominaisuusjoukon virtaa tai muokata XML-osaa käsin. Sijoitat merkkijonot ja päivämäärät työkirjaan, ja oikea säiliö syntyy sille muodolle, jossa tallennat

HotXLS Delphi -kaavio vertailee BIFF SummaryInformation -tallennusta ja OOXML docProps -osia Excel-asiakirjan ominaisuuksille
HotXLS litistää kaksi toisiinsa liittymätöntä tallennusmallia yhdeksi työkirjaominaisuuspinnaksi — moottori valitsee fyysisen säiliön, kun tiedosto tallennetaan

Tuotettujen työkirjojen leimaaminen liiketoimintatietueen perusteella

XLSX-puolella TXLSXWorkbook tarjoaa merkkijonoina ominaisuudet Title, Subject, Author, Keywords, Description, Category, LastModifiedBy, Company, Application ja AppVersion sekä TDateTime-arvoina ominaisuudet Created ja Modified, joissa nolla tarkoittaa asettamatonta arvoa. Perinnän aukon sulkeva sääntö on yhden virkkeen mittainen: aseta jokainen kenttä jokaisella ajokerralla ja ota arvot liiketoimintatietueesta sen sijaan, että luottaisit siihen, mitä pohja sattui sisältämään

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

    // korvaa jokainen kenttä: kaikki koskematta jätetty
    // periytyy mallin suunnittelijalta
    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;

Keywords-kenttä palkitsee tavallista suuremman harkinnan. Hakujärjestelmät indeksoivat sen sanatarkasti, niin Windows Search, SharePoint kuin useimmat DMS-tuotteetkin, joten tilinumeron ja jakson sisältävä puolipisteillä erotettu käytäntö muuttaa jokaisen toimitetun työkirjan löydettäväksi tietueeksi ilman tietokantakierrosta. Sama ulottuvuus on myös rajoitus. Ominaisuudet kulkevat tiedoston jokaisen kopion mukana kauas niiden kirjoittaneen järjestelmän käyttöoikeusrajoitusten ulkopuolelle, joten henkilötiedot eivät kuulu sinne

Aikaleimapariin liittyy semantiikkaa, joka kannattaa määrittää käytännöksi eikä jättää tottumuksen varaan. Created tulee merkitä hetkeä, jolloin putkesi loi asiakirjan, ja sen tulee pysyä jäädytettynä. Modified on kenttä, jonka Excel päivittää aina, kun vastaanottaja tallentaa tiedoston, joten toimituksen jälkeen näiden kahden ero on myönteinen todiste siitä, että joku muokkasi työkirjaa jatkokäsittelyssä. Tämä ratkaisee useammankin kiistan siitä, kenen luvut välitetyssä laskentataulukossa todella ovat. Asettamattomassa tilassa piilee yksi ansa: se on kirjaimellinen arvo nolla, ei poikkeus eikä null, joten auditointikoodin on testattava nolla erikseen. Jos muotoilet asettamattoman TDateTime-arvon ilman tätä suojausta, lokisi täyttyvät itsevarmasti vääristä joulukuun 1899 päivämääristä

DocPropsTouched: työkirja, joka toimitetaan ilman docProps-osia

Vain luku -lippu DocPropsTouched ohjaa XLSX-ominaisuuksien kirjoittajaa. Työkirja, johon ei koskaan sijoitettu mitään ominaisuutta, ei tuota lainkaan docProps-osia; HotXLS kieltäytyy kirjoittamasta tyhjää metatietorunkoa. Käytös on siistiä, ja sillä on kaksi seurausta, jotka kannattaa ottaa suunnittelussa huomioon

Vastaanottavan puolen vastaanottokoodi ei saa olettaa, että core.xml on jokaisessa paketissa. Työkalu, joka vaatii sen ehdottomasti, hylkää täysin kelvollisia vähimmäistiedostoja. Jos vaatimustenmukaisuuskäytäntösi edellyttää, että jokaisessa lähtevässä asiakirjassa on vähintään generaattorin tunniste, vaatimus muuttuu koodiksi eikä tiedostomuodon ominaisuudeksi: aseta Application ja Author ehdoitta tallennuspolulla, sillä koskematon työkirja on täysin laillinen määrityksen mukaan mutta rikkoo hiljaisesti käytäntöäsi

HotXLS Delphi -virtauskaavio, joka näyttää DocPropsTouched-lipun portittavan docProps-tulosteen tallennetuissa XLSX-työkirjoissa
DocPropsTouched portittaa XLSX-docProps-kirjoittajan — sijoita Application ja Author ehdoitta, kun käytäntö vaatii generaattorin identiteetin

Vanhan XLS-muodon ominaisuuspinta ja Comments-ansa

BIFF-julkisivu tarjoaa vanhemman ja pienemmän kenttäjoukon: Title, Subject, Author, Keywords, Comments, Company ja Manager sekä LastSavedBy-ominaisuuden, joka on UserName-aliaksen ja kirjoittaa WRITEACCESS-tietueen, jonka Excel näyttää, kun toisella käyttäjällä on tiedosto lukittuna

var
  Legacy: IXLSWorkbook;     // reference-counted interface: no manual 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';   // BIFF WRITEACCESS -tietue

  Legacy.SaveAs('archive-1999-stamped.xls');
end;

Yksi nimien törmäys aiheuttaa toistuvaa sekaannusta. Asiakirjatason Comments-ominaisuus on tässä tiedoston ominaisuusvalintaikkunassa näkyvä vapaamuotoinen huomautus. Sillä ei ole mitään tekemistä solualueisiin täysin erillisen API:n kautta liitettävien piirtotason objektien eli solukommenttien kanssa. Koodikatselmointi, joka hyväksyy väitteen ”kirjoitamme jo Comments-arvoja” tarkistamatta, mitä niistä tarkoitetaan, on hyväksynyt väitteen väärästä ominaisuudesta, ja tätä tapahtuu useammin kuin yhteinen nimi antaisi olettaa. Molemmilla on neljä samaa kirjainta eikä yhtäkään samaa tallennustavua

Metatietojen lukeminen vastaanotossa ja luotausaukko

Lukeminen on symmetristä. Open-kutsun jälkeen samat ominaisuudet täyttyvät tiedoston arvoista, joten saapuvien työkirjojen metatietojen auditoinnista tulee lyhyt silmukka

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;

Suunnittele yksi rajoitus huomioon ottaen. Pelkästään ominaisuuksia lukevaa luotausta ei ole. GetSheetNames voi luetella arkit lataamatta työkirjaa, mutta Title- tai Author-arvon lukeminen edellyttää täyttä Open-kutsua, joten suuren arkiston metatietojen lajittelu maksaa koko jäsennyskustannuksen jokaisesta tiedostosta. BIFF-puolella voit pienentää tätä kustannusta vain luku -auditoinneissa asettamalla _DisableGraphics-ominaisuuden todeksi ennen avaamista, jolloin piirtotaso ohitetaan kokonaan. Se sopii silmukkaan, joka lukee vain ominaisuuksia ja solutilastoja, ja on täysin väärin heti, kun sama instanssi saattaa tallentaa, sillä ohitettu piirtosisältö putoaisi pois. Kun arkkirakenne yksin voi esisuodattaa joukon, esimerkiksi yksittäisen arkin viennit on selvästi ohitettava, arkkien luetteloa ja kevyttä tarkastusta käsittelevän artikkelimme edulliset tekniikat vähentävät kalliiseen vaiheeseen päätyvien tiedostojen määrää. Ja tuhansia tulosteita kirjoittavissa massaleimaustöissä eräajojen suoratoistokirjoitusta käsittelevän artikkelimme kirjoituspuolen läpimenomallit toimivat sellaisenaan, sillä ominaisuuksien sijoittaminen ei lisää mitattavaa aikaa tallennukseen

Muotojen ylittäminen ja vuodon rajaaminen

Ominaisuudet kulkevat edestakaisin siististi yhden julkisivun sisällä: avaa .xlsx, muokkaa sitä, tallenna se, ja ominaisuusjoukko säilyy. Muotojen ylitys on kohta, jossa oletus vastaavuudesta hajoaa, koska BIFF- ja OOXML-kenttäjoukot eivät vastaa toisiaan yksi yhteen. BIFF sisältää Manager-ominaisuuden mutta ei aikaleimoja; OOXML sisältää Category-, Description- ja Created/Modified-parin. Sokeasti kopioiva muunnin menettää kaiken, mitä kohdemuoto ei voi sisältää, joten kartoita kentät erikseen ja lisää kartoitus muunnoksen tarkistusluetteloon kaiken muun rinnalle, mikä ei selviä matkasta

HotXLS Delphi -kenttäkartta, joka näyttää mitkä Excel-asiakirjan ominaisuudet selviävät muotojen välisestä muunnoksesta XLS:n ja XLSX:n välillä
Sokea muotojen välinen kopio pudottaa jokaisen kentän, jota kohde ei voi kantaa — mappaa BIFF- ja OOXML-ominaisuusjoukot eksplisiittisesti muunnostarkistuslistaan

Pohjaperinnän avaama vuoto kulkee toiseen suuntaan: tietoja, joita et koskaan tarkoittanut lähettää. Tekijöiden nimiä, avainsanoihin jätettyjä sisäisiä projektinimiä tai luonnosotsikko, jota kukaan ei tyhjentänyt. Yllä olevan generaattorin ylikirjoita-kaikki -käytäntö on koko puolustus, ja se kannattaa varmentaa ulkopuolisen tavoin avaamalla asiakkaan käytettävissä oleva Ominaisuudet-valintaikkuna tai purkamalla .xlsx-tiedosto ja lukemalla docProps/core.xml suoraan paketista. Se, mitä näet siellä, on täsmälleen se, mitä jokainen jatkopään indeksoija näkee

Tämä jatkopään näkyvyys on myös syy siihen, että muutama kenttä ansaitsee muita enemmän huolellisuutta. Title, Author, Keywords (joka näkyy Tags-kenttänä) sekä Comments tai Description kantavat suurimman osan indeksointipainosta SharePointissa ja Windows Searchissa. Jokaiselle asiakirjalle aidosti erillinen Title, joka sisältää jakson ja tilin, parantaa löydettävyyttä enemmän kuin sen päälle kasattu kansioiden nimeämisjärjestelmä, ja se maksaa yhden sijoituksen tallennusta kohti

Asiakirjan ominaisuudet ovat edullisinta ammattimaista viimeistelyä, jonka tuotettu työkirja voi sisältää, ja yleisimmin toimitettu virhe silloin, kun kukaan ei omista niitä. Molemmat tässä kuvatut ominaisuuspinnat kuuluvat HotXLS Delphi Component -komponenttiin, joka kirjoittaa ne natiivisti XLS- ja XLSX-muodoille ilman Excel-automatisointia