Документация HotXLS

Внешние ссылки на книги

Обзор

Табличные модели часто получают данные из вторичных книг с использованием формул перекрёстных ссылок; HotXLS поддерживает разбор, запись и сохранение внешних ссылок на книги как в документах BIFF8 (классический XLS), так и в OpenXML (XLSX)

Рабочая область активных книг

TXLSWorkbookWorkspace в модуле lxWorkbookWorkspace — общее ядро идентификации и регистрации активных внешних книг; и TXLSWorkbook, и TXLSXWorkbook открывают CreateWorkspaceWorkbook и владеют ExternalWorkspace, который используют их вычислители формул, а книга ODS, открытая через TXLSXWorkbook, сообщает вид движка OpenDocument через тот же адаптер

var
  Host, Target: TXLSXWorkbook;
begin
  Host.ExternalWorkspace.Add(
    '..\Data\Target.xlsx',
    '..\Data\Target.xlsx',
    'C:\Models\Host.xlsx',
    Target.CreateWorkspaceWorkbook);

  // The compatibility facade maps an unambiguous name to the
  // relationship target already stored in Host.ExternalLinks
  Host.RegisterExternalWorkbook('Target.xlsx', Target);

  // The matching call revokes a facade-level registration
  Host.UnregisterExternalWorkbook('Target.xlsx');
end;

Классические книги используют те же совместимые методы с целями TXLSWorkbook; RegisterExternalWorkbook и UnregisterExternalWorkbook управляют только отображением имён на уровне фасада, а ExternalWorkspace.Remove и Clear отзывывают сами регистрации рабочей области. Вызывающий код междвижковых сценариев добавляет любой адаптер Classic, XLSX или ODS прямо в ExternalWorkspace

  • Нормализация идентификации лексическая и без учёта регистра: она сохраняет пути и расширения, разрешает относительные цели относительно исходной идентификации владельца, сворачивает сегменты с точками и не выполняет доступа к файловой системе или сети
  • Первыми разрешаются точные идентификации и явные псевдонимы; поиск только по имени файла завершается успехом, лишь когда совпадает ровно одна подключённая регистрация, иначе Resolve возвращает xlswrsConflict
  • Add отвергает коллизии по точному ключу, псевдониму и дублированию книги; разные полные пути и разные расширения могут сосуществовать
  • Remove и Clear отзывывают регистрации, а прямое уничтожение цели Classic или XLSX отключает её адаптер и ждёт активных читателей, прежде чем освободить модель
  • Внешние листы разрешаются по объявленному имени до позиционного резерва с нумерацией с единицы, поэтому порядок листов целевой книги не обязан совпадать с каталогом ссылок источника
  • Вычислитель формул сначала читает разрешённую живую книгу и лишь затем обращается к типизированному кэшу файла-хозяина; хозяева Classic XLS декодируют разреженные значения XCT и CRN, а хозяева XLSX используют кэш внешних ссылок, уже имеющийся у модели пакета
  • OnLoadWorkbook — необязательный управляемый запрос ресурса; по умолчанию он равен nil, поэтому пересчёт по-прежнему не обращается к файловой системе и сети, пока код приложения явно не предоставит такую политику
  • Каждая нормализованная идентификация вызывает загрузчик не более одного раза до ResetLoadAttempts; параллельные запросы верхнего уровня разделяют выполняющийся результат, включая типизированные исходы «не найдено» и «ошибка», вместо того чтобы открывать один и тот же ресурс повторно
  • MaxLoadDepth по умолчанию равен 16, а MaxWorkbookCount — 64; повторный вход с той же идентификацией, вложенные зависимости от уже выполняющейся идентификации, исчерпание глубины и лимита книг возвращают типизированные диагностики, не блокируясь в цикле загрузки
  • ODF external-source IRI остаются полными лексическими идентификациями, включая схемы URI и экранированные символы, но никогда не разрешают неявный доступ к файлам или сети
  • Конфликт идентификаций остаётся #REF!, чтобы устаревшие кэшированные данные не могли скрыть неоднозначную маршрутизацию; отсутствие кэшированной ячейки даёт пустое значение только тогда, когда файл объявляет корректный кэш для этого листа

Resolve выполняет поиск по зарегистрированным книгам, а затем необязательную управляемую загрузку; её исход — TXLSWorkspaceResolveStatus (xlswrsResolved, xlswrsNotFound, xlswrsConflict, xlswrsDisconnected, xlswrsLoadNotFound, xlswrsLoadLimit, xlswrsLoadLoop или xlswrsLoadError), а ResolveWithLoader дополнительно возвращает TXLSWorkspaceLoadDiagnostic, сопоставляющий TXLSWorkspaceLoadDiagnosticCode с TXLSWorkspaceLoadResponseStatus (xlswlrsNotFound, xlswlrsResolved, xlswlrsError), чтобы различать исходы «не найдено», «ошибка загрузчика», «отключённая книга», «лимит глубины или числа книг», «повторный вход по идентификации», «параллельная зависимость» и «конфликт регистраций». Callback загрузчика получает TXLSWorkspaceLoadRequest (идентификация, глубина, число регистраций, лимиты) и отвечает TXLSWorkspaceLoadResponse

Recalculate сообщает TXLSWorkspaceRecalcStatus и, при желании, разбивку TXLSWorkspaceRecalcResult, а вычислитель записывает происхождение каждой ячейки как TXLSWorkspaceRuntimeLookup (xlswrlInactive, xlswrlResolved, xlswrlFallbackCache или xlswrlError), чтобы диагностика отличала живое чтение от fallback к кэшу

Адаптер IXLSWorkspaceWorkbook открывает EngineKind (тип TXLSWorkspaceEngineKind: xlsweClassic, xlsweOpenXml или xlsweOpenDocument), SourceIdentity, InstanceIdentity и Generation, проверяет живость через IsConnected, читает одну ячейку через TryGetCellValue (возвращает типизированный TXLSWorkspaceCellStatus: значение, отсутствие, некорректная ссылка, отключённая книга или ошибка плюс флаг выхода за используемый диапазон), обновляет модель через Recalculate и отсоединяется от модели книги через Disconnect

Реестр добавляет AddAlias для дополнительных имён, привязанных к одной зарегистрированной идентификации, TryResolve как вариант поиска без исключений и BaseNameMatchCount, чтобы заранее увидеть, сколько подключённых регистраций разделяют базовое имя, прежде чем выбирать однозначную цель

Граф зависимостей между книгами

BuildDependencyGraph делает снимок каждого зарегистрированного адаптера книги и извлекает узлы формул из моделей Classic XLS, XLSX и ODS в один TXLSWorkspaceDepGraph; метод возвращает False и не возвращает частичный граф, если какой-то зарегистрированный адаптер не может предоставить метаданные зависимостей

  • Каждый узел формулы хранит каноническую идентификацию книги, имя листа и позицию листа с нумерацией с единицы, позицию ячейки с нумерацией с нуля, прямоугольник вывода массива, волатильность и состояние неразрешённых ссылок
  • Ссылки на ячейки и прямоугольные диапазоны сохраняют канонические идентификации целевой книги и листа; ссылки на целый столбец, целую строку и целый лист остаются одним интервалом, а не разворачиваются в миллионы ячеек
  • Локальные определённые имена остаются доступными для запроса как символьные зависимости и при этом разворачиваются в конкретные зависимости по ячейкам или диапазонам, если определение можно разрешить статически
  • Внешние определённые имена сохраняют слот внешней ссылки, объявленное имя, необязательную область листа и каноническую идентификацию цели, не принимая метаданные DDE, OLE или пользовательских функций за имена книг
  • FindDependentsOfCell и построение рёбер графа используют деревья интервалов строк с отсечением по максимальному концу; LastRangeCandidateChecks и EdgeCandidateChecks раскрывают число точных проверок прямоугольников для проверки производительности
  • Извлечение формул выполняется под арендой чтения книги и сканирует только материализованные объекты формул, поэтому упакованное хранилище значений остаётся упакованным, а создание графа не меняет поколения книг

Плановый пересчёт

Recalculate сохраняет общий граф и перестраивает его, только когда меняется регистрация в рабочей области или поколение зависимостей формул книги; поколения значений запускают новый проход по изменённым узлам, а изменённость распространяется по рёбрам зависимостей между книгами

var
  RecalcInfo: TXLSWorkspaceRecalcResult;
  Status: TXLSWorkspaceRecalcStatus;
begin
  Status := Workspace.Recalculate(RecalcInfo);
  if Status <> xlswrcOk then
    HandleWorkspaceCalculation(Status, RecalcInfo);
end;
  • Сильно связанные компоненты вычисляются по ячейкам с формулами, поэтому книги могут ссылаться друг на друга в обе стороны, оставаясь ациклическими, пока пути зависимостей на уровне ячеек не образуют цикл
  • Настоящие участники цикла и изменённые потомки, заблокированные циклом, инвалидируются и исключаются из топологического порядка, чтобы устаревшие кэшированные значения не выдавались за успешный результат
  • Волатильные или статически неразрешимые ссылки принуждают консервативное поведение пересчёта, необходимое для корректности, а стабильные графы повторно используют прежнюю работу по зависимостям
  • Внешние чтения внутри прохода используют точный кэш по экземпляру книги, листу, строке и столбцу; плановая формула инвалидирует свой выходной диапазон до вычисления, чтобы позднейшие зависимые узлы увидели новое значение
  • Локальный для прохода кэш никогда не даёт права на доступ к ресурсам; зарегистрированные книги и необязательный управляемый вызывающей стороной загрузчик остаются единственными живыми источниками разрешения, за которыми следуют типизированные файловые кэши и #REF!
  • TXLSWorkspaceRecalcResult раскрывает признак перестроения графа, а также счётчики изменённых, вычисленных, инвалидированных узлов, циклов, заблокированных узлов, попаданий и промахов кэша
  • Статус различает успех, неподдерживаемые адаптеры, отключённые книги, циклические ссылки, ошибки вычисления и изменение рабочей области во время прохода
  • Вызовы Recalculate одной рабочей области сериализуются, поэтому две сессии вычисления никогда не изменяют общий граф и кэши книг параллельно
  • Remove и Clear могут выполняться, пока проход активен; проход хранит безопасные снимки адаптеров и возвращает xlswrcWorkspaceChanged вместо разыменования отозванной регистрации
  • Уничтожение рабочей области ждёт завершения активного прохода, а уничтожение зарегистрированной книги отключает её адаптер и заставляет последующие разрешения безопасно завершаться неудачей
  • Сбои загрузчика и результаты «не найдено» кэшируются по одному разу на нормализованную идентификацию до ResetLoadAttempts, а неудавшееся вычисление сохраняет локальное изменённое состояние для явного повтора
  • Удерживаемый граф делает неизменённый повторный проход пропорциональным числу зарегистрированных книг, а не количеству формул; нерекурсивный анализ компонент и компактные рёбра диапазонов ограничивают глубокие и широкие модели объёмом материализованных метаданных формул

Отсоединение внешних определённых имён

ConvertExternalDefinedNamesToRefErrors предоставляет одну и ту же открытую операцию на TXLSWorkbook и TXLSXWorkbook; она возвращает число определений уровня книги и уровня листа, заменённых #REF!

var
  Converted: Integer;
begin
  Converted := Workbook.ConvertExternalDefinedNamesToRefErrors;
  // External-link parts and ordinary cell formulas remain intact
end;
  • Выборка в Classic XLS использует скомпилированные BIFF-токены ссылок и идентификацию вспомогательной книги XTI, поэтому трёхмерные ссылки внутри той же книги и сомнительные потоки токенов остаются нетронутыми
  • Выборка в XLSX использует числовые слоты книг с учётом синтаксиса в порядке документов отношений и принимает только части внешних ссылок книг, исключая DDE, OLE, неразрешённые слоты, ссылки на таблицы и текст в квадратных скобках внутри строк
  • Все замены готовятся до первого изменения и фиксируются как одна операция записи; повторный вызов идемпотентен
  • Текст имени, область книги или листа, видимость, комментарии, флаги макросов и встроенных имён, неизвестные атрибуты XLSX и каталог внешних ссылок остаются доступны после преобразования и Roundtrip
  • Некорректные и неподдерживаемые определения по возможности сохраняются побайтово или как текст, а вместо угадывания добавляется диагностика xlsDiagnosticDefinedNameConversionSkipped
  • Зависимые формулы при пересчёте дают соответствующее значение ошибки Excel, а корректный кэшированный результат обычной прямой внешней формулы остаётся доступным, если её живая книга позже отключится
  • Операция специфична для Excel и не переинтерпретирует семантику формул имён OpenDocument

Внешние ссылки в классическом XLS

В классических книгах XLS внешние ссылки хранятся в блоке глобального каталога с использованием записей EXTERNALBOOK и EXTERNNAME; HotXLS поддерживает эти каталоги во время циклов чтения и записи файлов, гарантируя, что ссылки на удалённые диапазоны сохраняются при циклах изменения

Внешние связи XLSX

Для книг OOXML сопоставление внешних ссылок управляется через части отношений; ознакомьтесь с деталями поддерживающих интерфейсов ниже