Tekninen artikkeli

Ketjutetut kommentit Excel-tiedostoissa Delphillä ja HotXLS:llä

Kun luot työkirjan Delphistä ja lisäät soluun huomautuksen perinteisellä kommentti-API:lla, Excel 365 tallentaa tekstin muistiinpanoina (Notes): vanhanaikaisena keltaisena laatikkona ilman vastauskenttää, tekijän profiilikuvaa tai ratkaisupainiketta. HotXLS kirjoittaa aitoja Excel 365 -ketjutettuja kommentteja käyttäen XLSX-moottorin AddThreadedComment- ja AddThreadedReply-metodeja. Se luo kullekin taulukolle erillisen xl/threadedComments/threadedCommentN.xml-osan ja rekisteröi jokaisen tekijän työkirjatason person-osaan, jotta koodisi kirjoittama keskustelu on sama objekti, johon tarkastaja vastaa Excelissä

Ero on tärkeä, sillä nämä kaksi toimintoa vain näyttävät samankaltaisilta. Muistiinpano on kelluva tekstilaatikko, kun taas ketjutettu kommentti on keskusteluhistoria, jolla on pysyvät tunnisteet, vastauspuu, tekijärekisteri ja valmis-tila – asiat, joihin tarkastustyönkulku todella perustuu. Tässä artikkelissa käydään ensin läpi OOXML-rakenne, koska kun näet nämä kaksi tallennusmallia rinnakkain, kaikki toiminnalliset erot Excelissä käyvät järkeen

Miksi kommenttini näkyvät muistiinpanoina Excel 365:ssä?

Lyhyt vastaus: kaksi eri sukupolven kommenttityyppiä jakaa saman taulukon, ja ne sijaitsevat täysin eri osissa pakettia. Perinteinen malli – jota AddComment käyttää – tallentaa tekstin tiedostoon xl/comments1.xml (sisältötyyppi application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) ja määrittää laatikon sijainnin VML-piirto-osassa xl/drawings/vmlDrawing1.vml. Tämä pari on peräisin ajalta ennen valintanauhaa. Excel 365 lukee sitä edelleen luotettavasti, mutta näyttää lopputuloksen "muistiinpanona" eikä tarjoa siihen ketjutusliittymää, koska tallennusrakenteessa ei ole mitään ketjutettavaa. Tekijä on pelkkä näyttömerkkijono, sijainti on VML-muoto, ja siinä on koko malli

Excel 365:ssä esitellyt ketjutetut kommentit ohittavat VML-kerroksen kokonaan. Jokaisella taulukolla, jossa on keskusteluja, on oma xl/threadedComments/threadedCommentN.xml-osansa sisältötyypillä application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml, ja työkirjalla on yksi yhteinen xl/person/person.xml-osa (sisältötyyppi ...spreadsheetml.people+xml), joka luettelee kunkin osallistujan kerran. HotXLS tarjoaa molemmat mallit samassa taulukossa: AddComment kirjoittaa edelleen perinteisen parin, kun taas AddThreadedComment kirjoittaa uudet osat. Jos tulosteesi näkyy muistiinpanoina, kutsuit ensimmäistä API:a kun tarkoitit toista. Perinteinen malli on edelleen oikea työkalu joihinkin tehtäviin – aiempi artikkeli solukommenteista ja hyperlinkeistä tarkastustyönkuluissa käsittelee sitä perusteellisesti, mukaan lukien XLS-puolen – mutta mikään siinä ei muutu ketjuksi

Mitä HotXLS kirjoittaa pakettiin

HotXLS mallintaa jokaisen vastauksen TXLSXThreadedComment-objektina, joka sisältää solukiinnityksen (Ref), GUID-muotoisen tunnisteen (Id), valinnaisen isäntätunnisteen (ParentId), tekijän tunnisteen (AuthorId) joka selviää henkilöluettelosta, näyttönimen (DisplayName), tekstiosan, valmis-lipun (Done) ja ISO-8601-muotoisen aikaleiman (DateTime). Tallennettaessa jokainen merkintä muuttuu <threadedComment>-elementiksi, jonka t-attribuutti sisältää tunnisteen, dT-attribuutti aikaleiman ja parentT-attribuutti – joka on vain alavastauksilla – isäntäkommentin tunnisteen. Excel rakentaa keskustelupuun yhdistämällä parentT-arvon t-arvoon; XML-rakenteessa ei ole sisäkkäisyyttä, vaan kyseessä on litteä lista viittauksineen

Henkilö-osa (person part) on se palanen, jonka useimmat käsin tehdyt toteutukset unohtavat. Jokaisen ketjutetun kommentin authorId:n on viitattava <person>-merkintään tiedostossa xl/person/person.xml, joka on kytketty työkirjan suhteisiin omalla sisältötyypin ylikirjoituksellaan – muuten Excelillä ei ole näyttönimeä näytettäväksi. HotXLS hoitaa rekisteröinnin automaattisesti: AddThreadedComment etsii tekijää työkirjan Persons-luettelosta näyttönimen perusteella ja luo uuden GUID-tunnisteen sisältävän merkinnän, jos sellaista ei ole, jotta saman tekijän peräkkäiset kommentit jakavat saman identiteetin. Taulukon suhteet saavat threadedComments-suhteen, työkirjan suhteet saavat henkilösuhteen, ja sisältötyyppien manifesti saa molemmat ylikirjoitukset ilman, että mikään tästä näkyy koodissasi

Vastausketjun rakentaminen AddThreadedComment- ja AddThreadedReply-metodeilla

AddThreadedComment luo keskustelun juuren: sen ParentId jää tyhjäksi, mikä merkitsee sen ketjun aloitukseksi. AddThreadedReply ottaa ParentRef-parametrin – solun viitteen, jossa juuri sijaitsee – etsii juuren kyseisestä kiinnityspisteestä ja asettaa uuden vastauksen ParentId-arvoksi juuren Id-arvon. Molemmat palauttavat uuden TXLSXThreadedComment-objektin, joten voit asettaa aikaleiman tai valmis-tilan juuri luomaasi objektiin:

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Root: TXLSXThreadedComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('forecast.xlsx');
    Sheet := Book.Sheets[0];

    // Keskustelun juuri; ParentId jää tyhjäksi
    Root := Sheet.AddThreadedComment(8, 3,
      'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
    Root.DateTime := '2026-07-06T09:12:00Z';

    // Vastaukset kiinnittyvät samaan soluun; ParentRef osoittaa juurisoluun
    Sheet.AddThreadedReply(8, 3, Root.Ref,
      'Pipeline export missed the EMEA renewals, re-running', 'Jan Kowalski');
    Sheet.AddThreadedReply(8, 3, Root.Ref,
      'Confirmed, refreshed figure lands tomorrow', 'Maria Ortiz');

    Book.SaveAs('forecast-reviewed.xlsx');
  finally
    Book.Free;
  end;
end;

Kaksi yksityiskohtaa tuossa listauksessa ansaitsee huomiota. Ensinnäkin, Root.Ref välitetään itse rakennetun merkkijonon sijaan: kirjaston luoma viite vastaa varmasti sitä, mitä AddThreadedReply etsii, mikä poistaa kokonaisen luokan kiinnitysvirheitä. Toiseksi, molemmat tekijät välitettiin pelkkinä näyttöniminä – henkilörekisteri, GUID-identiteetit ja authorId-kytkennät tapahtuivat kulissien takana. Avaa tallennettu tiedosto Excel 365:ssä, ja solukiinnitys, vastausjärjestys ja kaksi eri osallistujaa ovat kaikki toiminnassa: klikkaa Vastaa, ja Excel lisää kommentin samaan ketjuun, jonka koodisi aloitti

Keskustelun lukeminen takaisin: edestakainen toiminta

HotXLS tukee ketjutettujen kommenttien edestakaista lukua ja kirjoitusta (round-trip) versiosta 2.122.0 alkaen: tallennetun paketin avaaminen uudelleen rakentaa kunkin taulukon keskusteluluettelon ja työkirjan osallistujaluettelon osista, joten tunnisteet, vastauslinkit ja näyttönimet säilyvät täyden luku-kirjoitussyklin yli. Lukija jäsentää person.xml-tiedoston ennen taulukon sisältöä, minkä ansiosta jokainen authorId selvittää näyttönimensä latausvaiheessa. Jäsennetyt henkilötunnisteet säilytetään sellaisenaan sen sijaan, että ne luotaisiin uudelleen, joten työkirja säilyttää vakaat tekijäidentiteetit useiden edestakaisten kierrosten yli koodisi ja Excelin välillä

var
  i: Integer;
  Cmt: TXLSXThreadedComment;
begin
  Book.Open('forecast-reviewed.xlsx');
  Sheet := Book.Sheets[0];
  for i := 0 to Sheet.ThreadedComments.Count - 1 do
  begin
    Cmt := Sheet.ThreadedComments[i];
    if Cmt.ParentId = '' then
      Writeln('Root at ', Cmt.Ref, ' by ', Cmt.DisplayName, ': ', Cmt.Text)
    else
      Writeln('  reply by ', Cmt.DisplayName, ': ', Cmt.Text);
  end;
  Writeln('Participants: ', Book.Persons.Count);
end;

Litteän listan ja viittausten tallennusmalli näkyy tässä tarkoituksella: ThreadedComments luettelee vastaukset osajärjestyksessä, ja tyhjä ParentId tunnistaa kunkin juuren. Jos tarvitset puun muodon – esimerkiksi tarkastuslokin vientiä varten – ryhmittele ensin Ref-arvon mukaan ja ketjuta sitten ParentId arvoon Id kunkin solun ryhmässä. Tämä jäsennetyn tiedon säilyttämistoiminta on yksi esimerkki kirjaston laajemmasta periaatteesta; artikkeli teemojen, laajennusluetteloiden ja laskentaketjun häviöttömästä edestakaisesta käsittelystä käsittelee sitä, miten sama periaate pätee muuhun pakettiin

Ratkaistu-tila, aikaleimat ja tekijän identiteetti

Kolme attribuuttia kantaa tarkastuksen semantiikkaa, ja kaikki kolme ovat kirjoitettavissa palautettuihin objekteihin. Done kartoittuu done-attribuuttiin – Excel näyttää ratkaistun ketjun kutistettuna Avaa uudelleen -linkin kera. DateTime on ISO-8601 UTC -luontileima (dT); HotXLS korvaa sen kiinteällä paikkamerkillä, jos jätät sen tyhjäksi, jotta osa on aina validi, mutta todellinen aikaleima tekee ketjun historiasta luettavan, joten aseta se. Identiteettipuolella jokainen TXLSXPerson paljastaa ProviderId-kentän – tyypillisesti None paikallisesti luoduille merkinnöille – ja UserId-kentän, jonka voit täyttää UPN-tunnuksella tai sähköpostilla, kun sovelluksesi tietää sen:

var
  Root: TXLSXThreadedComment;
  Person: TXLSXPerson;
begin
  Root := Sheet.ThreadedComments.FindAt('D9');
  if Root <> nil then
    Root.Done := True;   // tallennetaan muodossa done="1"; Excel näyttää ketjun ratkaistuna

  Person := Book.Persons.FindByDisplayName('Maria Ortiz');
  if Person <> nil then
    Person.UserId := 'maria.ortiz@example.com';
end;

Yksi raja on sanottava suoraan: HotXLS kirjoittaa <mentions>-elementin tyhjänä. @-mainintoja – mekanismia, joka korostaa kollegan nimen kommenttitekstissä ja käynnistää ilmoituksen Microsoft 365:ssä – ei mallinneta, joten @-merkin sisältävä teksti tallennetaan tavallisena tekstinä. Automaattisesti luodussa tarkastustyökirjassa tämä on harvoin menetys, mutta jos työnkulkusi riippuu mainintailmoituksista, varaudu siihen, että ihminen lisää ne Excelissä. Tekijän identiteetti henkilö-osassa parittuu luontevasti työkirjatason alkuperäkenttien kanssa, joita käsitellään artikkelissa työkirjan metatiedoista ja dokumentin ominaisuuksista, missä loppuosa luodun tiedoston tarkastusketjusta sijaitsee

Mitä vanhemmat Excel-versiot tekevät ketjutetuille kommenteille?

Excel 2016 ja sitä vanhemmat versiot ovat peräisin ajalta ennen ketjutettua mallia, ja ne yksinkertaisesti ohittavat osat, joita ne eivät ymmärrä. Kun Excel 365 itse tallentaa ketjutetun keskustelun, se kirjoittaa myös perinteisen kommenttivarjon – paikkamerkkihuomautuksen, jossa lukee "[Threaded comment]..." – juuri siksi, että vanhemmat versiot näyttävät jotain kiinnitetyssä solussa. HotXLS kirjoittaa vain ketjutetut osat ilman perinteistä varjoa, joten koodisi kirjoittama tiedosto ei näytä lainkaan kommenttimerkkiä, kun se avataan Excel 2016:ssa. Jos yleisöösi kuuluu ennen 365-versiota olevia asennuksia ja merkinnän on oltava näkyvissä niissä, perinteinen AddComment-API on edelleen yhteensopiva kanava; vältä vain molempien mallien pinoamista samaan soluun testaamatta jokaista Excel-versiota, jolle toimitat, koska se, miten lukija sovittaa yhteen huomautuksen ja ketjun yhdessä solussa, on lukijan päätös, ei sinun

Toinen tiukka raja on itse tiedostomuoto. Ketjutetut kommentit ovat OOXML-rakenne, jolle ei ole vastinetta BIFF8-muodossa, joten HotXLS:n .xls-puolella ei ole ketjutettua API:a – työkirja, jonka on pysyttävä perinteisessä binäärimuodossa, rajoittuu perinteisiin muistiinpanoihin. Käytännössä päätöstaulukko on lyhyt: jos kirjoitat .xlsx-tiedostoa Excel 365:lle tai web-/mobiili-Excel-lukijoille, käytä AddThreadedComment-metodia saadaksesi aitoja keskusteluja; jos kohderyhmänä on Excel 2016 tai .xls, käytä AddComment-metodia ja hyväksy muistiinpanomalli; jos tarkastat saamaasi tiedostoa, tarkista sekä ThreadedComments ja Comments, sillä työkirja, joka on elänyt molemmissa maailmoissa, voi oikeutetusti sisältää molempia. Molempien sukupolvien täydellinen API-rajapinta on dokumentoitu HotXLS Delphi Excel Component -tuotesivulla