Внешние ссылки на книги
Обзор
Табличные модели часто получают данные из вторичных книг с использованием формул перекрёстных ссылок; 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 сопоставление внешних ссылок управляется через части отношений; ознакомьтесь с деталями поддерживающих интерфейсов ниже
- Класс TXLSXExternalLinks — API для вывода списка и обновления внешних ссылок электронной таблицы
- Интерфейс IXLSWorkbook — Свойства книги верхнего уровня
- Свойство IXLSRange.Formula — Чтение и запись межкнижных формул