Tehnični članek

Nitni komentarji v datotekah Excel z Delphijem in HotXLS

Če ustvarite delovni zvezek iz Delphija in celico označite s klasičnim API-jem za komentarje, Excel 365 vaše besedilo uvrsti pod Opombe (Notes): staromodno rumeno polje brez polja za odgovor, brez avatarja avtorja in brez gumba za razrešitev. HotXLS piše prave nitne komentarje (threaded comments) za Excel 365 prek metod AddThreadedComment in AddThreadedReply v pogonu XLSX, pri čemer izda namenski del xl/threadedComments/threadedCommentN.xml na list in registrira vsakega avtorja v delu person na ravni delovnega zvezka, tako da je pogovor, ki ga napiše vaša koda, isti objekt, na katerega ocenjevalec odgovori v Excelu

Razlika je pomembna, saj sta si ti dve funkciji le na videz podobni. Opomba je lebdeče besedilno polje; nitni komentar pa je zapis pogovora s stabilnimi identifikatorji, drevesom odgovorov, registrom avtorjev in zastavico za razrešitev — to so elementi, na katerih dejansko temelji delovni tok pregledovanja. V tem članku si najprej ogledamo strukturo OOXML, saj ko enkrat vidite oba modela shranjevanja vzporedno, vsaka razlika v vedenju znotraj Excela preneha biti skrivnostna

Zakaj so moji komentarji v Excelu 365 prikazani kot opombe?

Kratek odgovor: dve generaciji komentarjev si delita isto mrežo, vendar živita v povsem različnih delih paketa. Starejši (legacy) model, ki ga cilja metoda AddComment, shranjuje besedilo v xl/comments1.xml (tip vsebine application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml), oblaček pa pozicionira prek spremljajočega dela risbe VML, xl/drawings/vmlDrawing1.vml. Ta par je nastal pred trakom (ribbon); Excel 365 ga še vedno zvesto bere, vendar rezultat izriše kot "opombo" (note) in na njem ne ponuja uporabniškega vmesnika za nitne odgovore, saj v shrambi ni ničesar, kar bi lahko povezali v nit. Avtor je le prikazni niz, položaj je oblika VML in to je celoten model

Nitni komentarji, uvoženi z Excelom 365, popolnoma prezrejo plast VML. Vsak list s pogovorom nosi svoj lasten del xl/threadedComments/threadedCommentN.xml pod tipom vsebine application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml, delovni zvezek pa nosi en sam del xl/person/person.xml (tip vsebine ...spreadsheetml.people+xml), ki vsakega sodelujočega navede enkrat. Komponenta HotXLS izpostavlja oba modela na istem delovnem listu: metoda AddComment še naprej piše starejši par, AddThreadedComment pa piše nove dele. Če se vaš izhod prikaže kot opomba, ste poklicali prvi API, želeli pa drugega. Starejši model je za nekatera opravila še vedno pravo orodje — prejšnji članek o komentarjih celic in hiperpovezavah v delovnih tokovih pregledovanja ga podrobno obravnava, vključno s stranjo XLS — vendar se iz njega nič ne nadgradi v nit

Kaj HotXLS zapiše v paket

HotXLS modelira vsak odgovor kot objekt TXLSXThreadedComment, ki nosi sidro celice (Ref), identifikator v slogu GUID (Id), neobvezni ParentId, AuthorId, ki se razreši prek seznama oseb, zrcalo DisplayName, telo besedila, zastavico Done in ISO-8601 DateTime. Ob shranjevanju vsak vnos postane element <threadedComment>, katerega atribut t vsebuje identifikator, atribut dT časovni žig, atribut parentT — ki je prisoten le pri pododgovorih — pa poimenuje starševski identifikator. Excel rekonstruira drevo pogovora z usklajevanjem parentT s t; v XML ni gnezdenja, le raven seznam z referencami

Del z osebami (person part) je tisti del, ki ga večina ročno izdelanih implementacij pozabi. Vsak authorId v nitnem komentarju se mora razrešiti v vnos <person> v xl/person/person.xml, povezan v relacije delovnega zvezka z lastnim preglasom tipa vsebine — sicer Excel nima prikaznega imena za prikaz. HotXLS samodejno poskrbi za registracijo: AddThreadedComment poišče avtorja na seznamu delovnega zvezka Persons po prikaznem imenu in ustvari vnos z novim GUID-om, ko ta še ne obstaja, tako da si zaporedni komentarji istega avtorja delijo eno identiteto. Relacije delovnega lista dobijo relacijo threadedComments, relacije delovnega zvezka dobijo relacijo person, manifest tipov vsebin (content-types) pa prejme oba preglasa, ne da bi se karkoli od tega pojavilo v vaši kodi

Izdelava verige odgovorov z AddThreadedComment in AddThreadedReply

Metoda AddThreadedComment ustvari koren pogovora: njen ParentId ostane prazen, kamor označuje začetek niti. Metoda AddThreadedReply sprejme parameter ParentRef — referenco celice, kjer se nahaja koren — najde koren na tem sidru in označi ParentId novega odgovora z Id-jem korena. Obe vrneta nov TXLSXThreadedComment, tako da lahko nastavite časovni žig ali stanje razrešitve na pravkar ustvarjenem objektu:

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

    // Koren pogovora; ParentId ostane prazen
    Root := Sheet.AddThreadedComment(8, 3,
      'Q3 figure looks low against the pipeline export', 'Maria Ortiz');
    Root.DateTime := '2026-07-06T09:12:00Z';

    // Odgovori se sidrajo v isto celico; ParentRef poimenuje korensko celico
    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;

Dve podrobnosti v tem izseku si zaslužita pozornost. Prvič, posreduje se Root.Ref in ne ročno zgrajen niz: referenca, ki jo je ustvarila knjižnica, se zagotovo ujema s tisto, ki jo bo iskala metoda AddThreadedReply, relativno gledano, kar odpravlja celoten razred hroščev pri sidranju za eno mesto. Drugič, oba avtorja sta bila posredovana kot navadna prikazna imena — register oseb, identitete GUID in povezava authorId so se zgodili v ozadju klicem. Odprite shranjeno datoteko v Excelu 365 in sidranje celic, vrstni red odgovorov ter dva ločena sodelujoča so aktivni: kliknite Odgovori in Excel bo dodal odgovor v isto nit, ki jo je začela vaša koda

Branje pogovora nazaj: vedenje pri povratnem potovanju (round-trip)

HotXLS podpira povratno potovanje (round-trip) nitnih komentarjev od različice 2.122.0 dalje: ponovno odpiranje shranjenega paketa znova zgradi seznam pogovorov vsakega lista in seznam sodelujočih delovnega zvezka iz delov, tako da identifikatorji, povezave za odgovore in prikazna imena preživijo celoten cikel branje→pisanje. Bralnik razčleni person.xml pred vsebino katerega koli lista, kar omogoča, da se vsak authorId ob nalaganju razreši v prikazno ime; razčlenjeni identifikatorji oseb se ohranijo takšni, kot so, namesto da bi se znova ustvarili, zato delovni zvezek, ki potuje med vašo kodo in Excelom, ohranja stabilne identitete avtorjev skozi poljubno število povratnih poti

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('Koren pri ', Cmt.Ref, ' od ', Cmt.DisplayName, ': ', Cmt.Text)
    else
      Writeln('  odgovor od ', Cmt.DisplayName, ': ', Cmt.Text);
  end;
  Writeln('Participants: ', Book.Persons.Count);
end;

Shranjevanje v obliki ravnega seznama s sklici se tukaj namerno pozna: zbirka ThreadedComments našteva odgovore v vrstnem redu delov, prazen ParentId pa identificira vsak koren. Če potrebujete drevesno obliko — na primer za izvoz dnevnika pregledov — najprej razvrstite po Ref, nato pa znotraj skupine vsake celice povežite ParentId z Id. To vedenje ohranjanja razčlenjenega je en primer širše politike v knjižnici; članek o povratnem potovanju tem, seznamov razširitev in verige izračunov brez izgub opisuje, kako velja isto načelo za preostanek paketa

Stanje razrešitve, časovni žigi in identiteta avtorja

Trije atributi nosijo semantiko pregleda in vsi trije so zapisljivi na vrnjenih objektih. Lastnost Done se preslika v atribut done — Excel prikaže razrešeno nit strnjeno s povezavo Ponovno odpri (Reopen). Lastnost DateTime je časovni žig ustvarjanja ISO-8601 UTC (dT); HotXLS nadomesti fiksni nadomestni znak, ko ga pustite praznega, da se del vedno potrdi, vendar je pravi časovni žig tisti, ki naredi zgodovino niti berljivo, zato ga nastavite. Na strani identitete vsak TXLSXPerson izpostavi ProviderId — običajno None za lokalno ustvarjene vnose — in UserId, ki ga lahko napolnite z UPN ali e-pošto, ko ga vaša aplikacija pozna:

var
  Root: TXLSXThreadedComment;
  Person: TXLSXPerson;
begin
  Root := Sheet.ThreadedComments.FindAt('D9');
  if Root <> nil then
    Root.Done := True;   // shranjeno kot done="1"; Excel prikaže nit kot razrešeno

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

Ena omejitev, ki jo je treba odkrito povedati: HotXLS piše element <mentions> prazen. Zapisi omenjanja z @-mention — mehanizem, ki osvetli ime sodelavca znotraj besedila komentarja in sproži obvestilo v Microsoft 365 — niso modelirani, zato se besedilo, ki vsebuje znak @, shrani kot navadno besedilo. Za ustvarjen delovni zvezek za pregled je to le redko izguba, če pa je vaš delovni tok odvisen od obvestil o omeni, načrtujte, da jih bo človek dodal znotraj Excela. Identiteta avtorja v delu person se naravno povezuje s polji izvora na ravni delovnega zvezka, opisanimi v metapodatkih delovnega zvezka in lastnostih dokumenta, kjer živi preostanek revizijske sledi ustvarjene datoteke

Kaj starejše različice Excela storijo z nitnimi komentarji?

Excel 2016 in starejši so nastali pred nitnim modelom in preprosto prezrejo dele, ki jih ne razumejo. Ko sam Excel 365 shrani nitni pogovor, zapiše tudi starejšo senco komentarja — nadomestno opombo z besedilom "[Threaded comment]…" — prav zato, da starejše različice prikažejo nekaj na sidrani celici. Komponenta HotXLS oddaja le nitne dele brez starejše sence, zato datoteka, ki jo je napisala vaša koda, ob odpiranju v Excelu 2016 sploh ne prikazuje indikatorja komentarja. Če vaše občinstvo vključuje namestitve pred različico 365 in mora biti oznaka tam vidna, starejši API AddComment ostaja združljiv kanal; le izogibajte se zlaganju obeh modelov na isto celico brez testiranja vsake različice Excela, ki jo pošiljate, saj je to, kako bralnik uskladi opombo in nit na eni celici, odločitev bralnika in ne vaša

Druga trda omejitev je sam format datoteke. Nitni komentarji so struktura OOXML brez dvojnika v BIFF8, zato stran .xls komponente HotXLS nima nitnega API-ja — delovni zvezek, ki mora ostati v starejšem binarnem formatu, je omejen na klasične opombe. V praksi je odločitvena tabela kratka: ko pišete .xlsx za Excel 365 ali spletne/mobilne bralnike Excel, uporabite AddThreadedComment in dobili boste prave pogovore; ko ciljate na Excel 2016 ali .xls, uporabite AddComment in sprejmite model opomb; ko revidirate datoteko, ki ste jo prejeli, preverite tako ThreadedComments kot Comments, saj lahko delovni zvezek, ki je živel v obeh svetovih, upravičeno vsebuje oboje. Celotna površina API-ja za obe generaciji je dokumentirana na strani izdelka HotXLS Delphi Excel Component