HotXLS записывает книги ISO/IEC 29500 Strict Open XML из Delphi и C++Builder установкой одного свойства, StrictOOXML, перед сохранением. Каждая часть пакета, от xl/workbook.xml до файлов связей и типов содержимого, записывается со строгими словарями purl.oclc.org вместо переходных schemas.openxmlformats.org, а функции, не допустимые режимом Strict, отклоняются явным исключением, а не молча записываются в файл
Большинство разработчиков сталкиваются с этим требованием через закупочную документацию. Государственные тендеры в ряде юрисдикций требуют стандартизированную ISO форму Open XML, а не переходную форму, которую Office записывает по умолчанию, — и архив, требующий соответствия ISO 29500 Strict, отклонит обычный .xlsx, даже если Excel открывает его безупречно. Переходные пространства имён существуют для поддержки устаревшего двоичного поведения; строгие — это собственно сам стандарт
В чём на самом деле разница между Strict и Transitional?
Видимое различие — в словаре. Строгая часть книги объявляет http://purl.oclc.org/ooxml/spreadsheetml/main как корневое пространство имён и http://purl.oclc.org/ooxml/officeDocument/relationships для ссылок на связи, и ни одно переходное пространство имён не должно сохраниться нигде в пакете. Типы связей меняются вместе с ним, поэтому корневая часть связей называет .../ooxml/officeDocument/relationships/officeDocument, а не привычный эквивалент openxmlformats, а тип расширенных свойств пишется в camelCase как extendedProperties
Невидимое различие — в области охвата. Strict сознательно опускает части переходной схемы, существовавшие лишь для round-trip старых двоичных файлов, вместе с расширениями от Microsoft, добавленными позже. Именно поэтому конвертация — не поиск и замена по строкам: у некоторых функций просто нет строгого написания, и их вообще нельзя записывать
Как включить режим
Обычный код авторинга не меняется. Постройте книгу так, как обычно, установите флаг и сохраните:
var
Wb: TXLSXWorkbook;
Sh: TXLSXWorksheet;
begin
Wb := TXLSXWorkbook.Create;
try
Sh := Wb.Sheets.Add('Data');
Sh.Cells[1, 1].Value := 'Product';
Sh.Cells[1, 2].Value := 'Amount';
Sh.Cells[2, 1].Value := 'Widget';
Sh.Cells[2, 2].Value := 17;
Sh.Cells[3, 2].Formula := '=SUM(B2:B2)';
Wb.StrictOOXML := True; // вывод ISO/IEC 29500 Strict
if Wb.SaveAs('archive-copy.xlsx') <> 1 then
raise Exception.Create('strict save failed');
finally
Wb.Free;
end;
end;
Флаг сбрасывается в начале каждой операции сохранения и переустанавливается из свойства книги, поэтому исключение при одном сохранении не может допустить утечку строгого режима в следующее. Эта деталь важна в серверных процессах, где один объект книги обслуживает несколько запросов на экспорт
Почему строгое сохранение может отказаться выполняться?
Четыре семейства функций — это расширения Microsoft, не имеющие эквивалента в ISO 29500 Strict, и HotXLS выбрасывает исключение во время сохранения, а не выдаёт пакет, который заявляет о строгом соответствии, но им не является:
// Строгий вывод не может встроить проект VBA
// -> сохраняйте книги с макросами как переходные .xlsm
// Строгий вывод не может нести элементы управления формы
// -> кнопки, флажки, выпадающие списки и их ctrlProps
// Строгий вывод не может нести потоковые комментарии
// -> современную модель persons/threads, а не классические заметки
// Строгий вывод не может нести метаданные динамических массивов
// -> диапазоны разлива, записанные через часть метаданных
Громкий отказ — правильный компромисс здесь. Молча отброшенный проект VBA превращает рабочую книгу в сломанную, которая всё же открывается, а отчёт о сбое приходит от пользователя спустя недели. Исключение называет и функцию, и свойство для изменения, пока вызывающий код ещё помнит, что он экспортировал. Сохранение макросов и внешних связей на переходном пути описано в статье сохранение проектов VBA и внешних связей
Два семейства расширений обрабатываются иначе, и стоит понимать почему. Гистограммы данных, спарклайны и подобные функции живут в словарях x14 и xm, а SVG-варианты изображений — в c15. Это содержимое списка расширений, чьи пространства имён самоописываемые, обычные парсеры электронных таблиц их допускают, и им нет эквивалента ISO для перевода. HotXLS сохраняет их, а не отбрасывает пользовательское содержимое. Если валидатор в вашем конвейере строг также и в отношении расширений, а не только пространств имён, удалите эти функции из исходной книги перед экспортом
Перевод должен добраться до частей, которые обычно никто не переписывает
Интересная инженерная проблема в строгом выводе — не XML листа. Это части, которые быстрый писатель предпочёл бы скопировать дословно. HotXLS сохраняет темы, подключения, внешние связи, диаграммы и блобы сводных таблиц, копируя их исходные сжатые байты напрямую, что абсолютно правильно для точности и абсолютно неправильно для строгого вывода, поскольку скопированные байты несут переходные пространства имён
Под StrictOOXML эти пять сохраняемых путей переключаются на пересборку или переводящий повтор, минуя быстрый путь побайтового копирования. Весь XML проходит через единую процедуру перевода, которая привязывается к значениям атрибутов в двойных кавычках, так что строка, похожая на URI, внутри ячейки, никогда не будет случайно переписана. Текст ячейки, содержащий тот же URI, экранируется как сущность в XML, поэтому привязанная замена не может его увидеть. Потоковый писатель сначала переводит свой скелет, а затем разбивает на sheetData, поскольку блоки строк вообще не содержат URI словарей. Смежная механика для пути сохранения описана в статье беспотерянный round-trip тем, списков расширений и calcChain
Чтение файлов, сохранённых Excel в строгом режиме
Вывод — это лишь половина истории. Excel предлагает "Строгая электронная таблица Open XML" в качестве варианта сохранения, и файлы, созданные таким образом, должны открываться корректно. HotXLS нормализует типы связей в каждом месте разбора связей внутри пакета — корневом, внешних связях, листах, рисунках и сводных таблицах, — так что строгий тип связи сопоставляется с той же внутренней константой, что и его переходный аналог
Аналог на стороне чтения — нормализация префиксов пространств имён, что позволяет произвольным префиксам и обеим словарям разрешаться в одну каноническую таблицу имён. Эта работа полезна как для обычных файлов, так и для строгих, поскольку сторонние генераторы привязывают префиксы произвольно, и это та же механика, что описана в статье разрешение связей OPC в пакетах XLSX
Краткий чек-лист перед публикацией строгого вывода
Проверяйте по пакету, а не по Excel. Excel благополучно открывает обе формы, поэтому успешное открытие ничего не доказывает в отношении соответствия. Распакуйте результат и убедитесь, что xl/workbook.xml объявляет пространство имён purl, что ни одна часть не содержит schemas.openxmlformats.org/spreadsheetml, и что типы связей в _rels/.rels и xl/_rels/workbook.xml.rels используют строгие формы
Затем откройте файл заново через HotXLS и сравните значения, формулы, форматы и гиперссылки с исходником. Тест обратного чтения — единственный дешёвый способ доказать, что перевод не повредил содержимое, и он одновременно проверяет нормализацию на стороне чтения. Если в ваших книгах есть диаграммы, проверьте и их, поскольку часть диаграммы — одна из сохраняемых частей, переключающихся на пересобранный путь в строгом режиме
Строгий вывод, толерантное чтение и беспотерянное сохранение — всё это часть одного движка OOXML для Delphi и C++Builder; полный список возможностей — на странице компонента HotXLS для электронных таблиц Delphi