Техническа статия

Нишковидни коментари (Threaded Comments) в Excel файлове с Delphi и HotXLS

Ако генерирате работна книга от Delphi и добавите коментар към клетка чрез класическия приложен програмен интерфейс (API) за коментари, Excel 365 ще запише вашия текст в секцията Notes – класическото жълто поле без поле за отговор, аватар на автора или бутон за маркиране като разрешен. HotXLS създава истински нишковидни коментари (threaded comments) за Excel 365 чрез методите AddThreadedComment и AddThreadedReply във XLSX ядрото си. Той генерира съответния XML файл xl/threadedComments/threadedCommentN.xml за всеки лист и регистрира всеки автор в списъка с лица (person) на ниво работна книга, така че разговорът, записан от вашия код, е същият обект, на който рецензентът отговаря в Excel

Разликата е важна, тъй като тези две функции само си приличат визуално. Бележката (note) представлява плаващо текстово поле; нишковидният коментар (threaded comment) е запис на разговор със стабилни идентификатори, дърво на отговорите, списък с автори и флаг за разрешен статус – елементите, на които реално се базира един процес на рецензиране. Табличното съдържание и разпределение на коментарите са разгледани в тази статия, тъй като след като се запознаете с двата модела за съхранение, разликата в поведението им в Excel става напълно логична

Защо коментарите ми се показват като бележки (Notes) в Excel 365?

Краткият отговор: две поколения коментари споделят една и съща работна таблица, но се съхраняват в напълно различни части от пакета на файла. Остарелият модел – този, към който е насочен методът AddComment – записва текста в xl/comments1.xml (тип съдържание application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml) and positions the balloon through a companion VML drawing part, xl/drawings/vmlDrawing1.vml. Тази двойка файлове е от времето преди интерфейса с лента (ribbon); Excel 365 все още ги чете коректно, но визуализира резултата като бележка (note) и не предлага интерфейс за отговори, тъй като в структурата липсват данни за нишки. Авторът е просто текст за показване, а позицията е VML фигура – това описва целия модел

Нишковидните коментари, въведени в Excel 365, напълно игнорират VML слоя. Всеки лист с разговор съдържа собствен файл xl/threadedComments/threadedCommentN.xml под типа съдържание application/vnd.openxmlformats-officedocument.spreadsheetml.threadedComments+xml, а работната книга съдържа един-единствен файл xl/person/person.xml (тип съдържание ...spreadsheetml.people+xml), описващ всеки участник веднъж. HotXLS поддържа и двата модела за един и същ работен лист: AddComment продължава да използва остарялата структура, докато AddThreadedComment записва новите части. Ако резултатът ви се показва като бележка, вие сте извикали първия приложен интерфейс, вместо втория. По-старият модел все още е подходящ за определени задачи – предходната статия за коментари на клетки и хипервръзки в процеси на рецензиране го описва подробно, включително за формата XLS – но елементите в него не могат да бъдат превърнати в нишка

Какво записва HotXLS в пакета на файла

HotXLS моделира всеки отговор като обект TXLSXThreadedComment, съдържащ връзка с клетка (Ref), идентификатор в стил GUID (Id), незадължителен ParentId, AuthorId, който се свързва със списъка с лица, име за показване (DisplayName), самия текст, флаг за разрешен статус Done и дата/час DateTime по ISO-8601. При запис всеки коментар се превръща в XML елемент <threadedComment>, чийто атрибут t пази идентификатора, dT пази времето на създаване, а parentT – наличен само за под-отговорите – сочи към идентификатора на родителя. Excel реконструира йерархията на разговора чрез свързване на parentT с t; в XML кода няма вложени структури, а само плосък списък и препратки

Записът за лица (person) е елементът, който повечето ръчни имплементации пропускат. Всеки authorId в нишковиден коментар трябва да съответства на запис <person> в xl/person/person.xml, свързан с връзките на работната книга и имащ собствен тип съдържание – в противен случай Excel няма да може да покаже име на автора. HotXLS управлява тази регистрация автоматично: методът AddThreadedComment проверява за автора в списъка Persons на работната книга по име за показване и създава нов запис с нов GUID, ако такъв не съществува. По този начин последователни коментари от един автор споделят една обща идентичност. Връзките на работния лист се допълват с релацията threadedComments, връзките на работната книга – с релацията за лица, а манифестът с типове съдържание получава и двете нови дефиниции, без нищо от това да изисква писане на допълнителен код

Изграждане на нишка с отговори чрез AddThreadedComment и AddThreadedReply

Методът AddThreadedComment създава корена на разговора: неговият ParentId остава празен, което го определя като начало на нишката. Методът AddThreadedReply приема параметър ParentRef – референцията за клетката, в която живее коренът, намира корена по тази позиция и задава за ParentId на новия отговор съответния Id на корена. И двата метода връщат новия обект TXLSXThreadedComment, което ви позволява да настроите времето на създаване или статуса за разрешена тема директно върху него:

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

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

    // Replies anchor at the same cell; ParentRef names the root cell
    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;

Два детайла в горния пример заслужават внимание. Първо, предава се свойството Root.Ref вместо ръчно конструиран низ: генерираната от библиотеката референция гарантирано съответства на това, което AddThreadedReply ще търси, предотвратявайки грешки при свързването с клетките. Второ, имената на двамата автори се предават като стандартни низове – регистърът на лицата, идентичността на GUID и свързването с authorId се извършват изцяло фоново в методите. Отворете записания файл в Excel 365 и позиционирането в клетките, подредбата на отговорите и двамата участници са активни: изберете бутона Reply и Excel ще добави нов отговор към същата нишка, създадена от вашия код

Прочитане на разговора обратно: поведение при двупосочно четене и запис

HotXLS поддържа пълна съвместимост за нишковидни коментари от версия v2.122.0 насам: отварянето на записания пакет реконструира списъка с коментари за всеки лист и списъка с участници за работната книга, така че идентификаторите, връзките за отговори и имената на авторите се запазват напълно. Четецът анализира person.xml преди съдържанието на работните листове, което позволява на всеки authorId да се свърже с име за показване при зареждане; прочетените идентификатори на лица се запазват непокътнати, вместо да се генерират наново, благодарение на което работна книга, преминаваща между вашия код и Excel, запазва стабилна идентичността на авторите

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;

Структурата от плосък списък и препратки е видима в този модел: свойството ThreadedComments изброява отговорите по реда на тяхното разположение в XML файла, а празният ParentId дефинира всеки корен на разговор. Ако ви е необходима йерархична структура (например за извеждане на рецензионен дневник), първо групирайте елементите по Ref, а след това свържете ParentId с Id в рамките на всяка клетъчна група. Това поведение за запазване на прочетената структура е част от общата политика на библиотеката; статията за запазване на данни при двупосочно четене и запис за теми, списъци с разширения и изчислителната верига описва как този принцип се прилага в целия пакет на файла

Разрешен статус, време на създаване и идентичност на авторите

Три атрибута дефинират семантиката на рецензирането, като и трите са достъпни за писане. Свойството Done съответства на атрибута done – Excel показва разрешените теми в свит вид с връзка за повторно отваряне (Reopen). Свойството DateTime пази UTC времето на създаване по ISO-8601 (dT); HotXLS записва подразбиращ се маркер, ако го оставите празно, за да гарантира валидността на файла, но задаването на реално време прави хронологията четима. Що се отнася до идентичността, всеки TXLSXPerson има свойство ProviderId (обикновено None за локално създадени автори) и UserId, което можете да попълните с имейл адрес, ако вашето приложение разполага с такъв:

var
  Root: TXLSXThreadedComment;
  Person: TXLSXPerson;
begin
  Root := Sheet.ThreadedComments.FindAt('D9');
  if Root <> nil then
    Root.Done := True;   // saved as done="1"; Excel shows the thread resolved

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

Едно ограничение трябва да се отбележи: HotXLS записва елемента <mentions> празен. Записите за споменавания (mentions с @) – функционалността, която маркира името на колега в текста на коментара и изпраща известие в Microsoft 365 – не са моделирани, така че текстът със знака @ се записва като обикновен текст. За автоматично генерирани работни книги това рядко е проблем, но ако вашият процес разчита на тези известия, планирайте добавянето им да бъде извършено ръчно от потребител в Excel. Идентичността на автора в частта за лица се съчетава логично с полетата на ниво работна книга, разгледани в метаданни на работна книга и свойства на документ, където се намира останалата част от одитната пътека

Какво правят по-старите версии на Excel с нишковидните коментари?

Excel 2016 и по-стари версии са отпреди въвеждането на нишковидния модел, поради което те просто игнорират частите от файла, които не разбират. Когато Excel 365 записва нишковиден коментар, той генерира и остаряло текстово копие – бележка маркер (placeholder note) с текст „[Threaded comment]…“, за да може по-старите програми да покажат нещо в клетката. HotXLS записва само нишковидните части без това текстово копие, така че файлът, записан от вашия код, няма да покаже индикатор за коментар при отваряне в Excel 2016. Ако вашите потребители използват версии преди Excel 365 и бележките трябва да се виждат, тогава остарелият приложен програмен интерфейс AddComment остава съвместимият метод; избягвайте използването на двата модела за една клетка без детайлно тестване, тъй като начинът на обединяване на бележка и нишка в една клетка зависи изцяло от четеца на файлове

Другото твърдо ограничение е самият файлов формат. Нишковидните коментари са OOXML структура без еквивалент в BIFF8, така че XLS ядрото на HotXLS няма API за нишки – работна книга, която се съхранява в остарелия двоичен формат, е ограничена до класически бележки. На практика изборът е лесен: при запис на .xlsx за Excel 365 или уеб/мобилни версии на Excel, използвайте AddThreadedComment за реални разговори; при насочване към Excel 2016 или .xls формат, използвайте AddComment за бележки; при анализ на файл проверете и двете свойства – ThreadedComments и Comments, тъй като файл, редактиран и в двете среди, може да съдържа и двете структури. Пълният приложен програмен интерфейс за двете поколения коментари е документиран на продуктовата страница за HotXLS Delphi Excel Component