Microsoft open xml converter что это

Обновлено: 04.07.2024

Содержание

Процесс стандартизации

Лицензирование

Microsoft безоговорочно обещает не предъявлять к вам никаких необходимых претензий Microsoft в связи с созданием, использованием, продажей, предложением к продаже, импортом или распространением любой реализации в той степени, в которой она соответствует Охваченной спецификации […]

Версии

Спецификация Office Open XML существует в нескольких версиях.

ECMA-376 1-е издание (2006 г.)

  • Словарь, условные обозначения и сокращения
  • Резюме основных и поддерживающих языков разметки
  • Условия соответствия и рекомендации по совместимости
  • Ограничения в рамках Open Packaging Conventions, применимые к каждому типу документов
  • В Соглашения об открытой упаковке (OPC) для модели пакета и физического пакета определяется и используется различными типами документов в различных приложениях от нескольких поставщиков.
  • Он определяет основные свойства, эскизы, цифровые подписи, а также возможности авторизации и шифрования для частей или всего содержимого пакета.
  • XML-схемы для OPC объявляются как определения XML-схемы (XSD) и (ненормативно) с использованием РЕЛАКС НГ (ИСО / МЭК 19757-2)
  • Информативное (ненормативное) введение в WordprocessingML, SpreadsheetML, PresentationML, DrawingML, VML и общие ML, обеспечивающие контекст и иллюстрирующие элементы с помощью примеров и диаграмм
  • Описывает настраиваемое средство хранения XML-данных в пакете для поддержки интеграции с бизнес-данными.
  • Содержит справочные материалы для WordprocessingML, SpreadsheetML, PresentationML, DrawingML, Shared ML и Custom XML Schema, определяя каждый элемент и атрибут, включая иерархию элементов (отношения родитель / потомок)
  • XML-схемы для языков разметки объявляются как XSD и (ненормативно) с использованием RELAX NG.
  • Определяет настраиваемое средство хранения данных XML
  • Описывает возможности расширения документов OpenXML и определяет элементы и атрибуты, с помощью которых приложения могут работать с различными расширениями.

Более поздние версии стандарта ECMA-376 согласованы и технически эквивалентны соответствующему стандарту ISO.

ISO / IEC 29500: 2008

Технически эквивалентный набор текстов также опубликован Ecma как ECMA-376 2nd edition (2008).

  • Определения соответствия
  • Справочные материалы по языкам разметки XML-документов, определенным стандартом
  • XML-схемы для языков разметки документов, объявленных с помощью XSD и (ненормативно) РЕЛАКС НГ
  • Определяет внешние средства разметки
  • Описание соглашений об открытой упаковке (модель упаковки, физическая упаковка)
  • Основные свойства, эскизы и цифровые подписи
  • XML-схемы для OPC объявляются с использованием XSD и (ненормативно) РЕЛАКС НГ
  • Описание расширения: элементы и атрибуты, которые определяют механизмы, позволяющие приложениям определять альтернативные средства согласования контента
  • Правила расширяемости выражаются с помощью NVDL
  • Устаревшие материалы, такие как настройки совместимости и язык разметки графики. VML
  • Список синтаксических различий между этим текстом и ECMA-376 1st Edition

Стандарт определяет два уровня соответствия документов и приложений, строгий и переходный для каждого из WordprocessingML, PresentationML и SpreadsheetML, а также определяет описания приложений основание и полный.

Совместимость версий

Поддержка приложения

Однако возможность чтения и записи в формате Office Open XML не ограничивается Microsoft Office; другие офисные продукты также могут читать и писать в этом формате:

Другие офисные продукты, которые предлагают поддержку импорта форматов Office Open XML, включают:

Open XML — это открытый стандарт для текстовых документов, презентаций и электронных таблиц, который может быть реализован в разных приложениях на различных платформах. Open XML позволяет точно представлять существующие текстовые документы, презентации и электронные таблицы, которые кодируются в двоичных форматах, используемых приложениями Microsoft Office. Причина популярности Open XML очевидна: теперь существуют миллиарды документов, но, к сожалению, данные в них тесно связаны с программой, в которой они были созданы. Цель стандарта Open XML — снять зависимость документов от приложений Microsoft Office, в которых они были созданы, чтобы с ними можно было работать в других приложениях независимо от формата и без потери данных.

Структура пакета Open XML

Файл Open XML хранится в ZIP-архиве, чтобы уменьшить размер файла. Структуру файла Open XML можно просмотреть с помощью средства просмотра ZIP-файлов. Документ Open XML состоит из нескольких частей документа. Отношения между частями хранятся в частях документа. Формат ZIP поддерживает произвольный доступ к каждой части. Например, приложение может переместить слайд из одной презентации в другую без синтаксического анализа содержимого слайда. Также приложение может удалить все примечания из текстового документа без анализа его содержимого.

Части документа в пакете Open XML создаются в виде разметки XML. Поскольку XML — это обычный структурированной текст, вы можете просмотреть содержимое части документа с помощью средства чтения текста или выполнить синтаксический анализ содержимого с помощью таких процессов, как XPath.

Структурно документ Open XML — это пакет Open Packaging Conventions (OPC). Как говорилось ранее, пакет состоит из набора частей документа. У каждой части есть имя, которое состоит из последовательности сегментов или пути, например "/word/theme/theme1.xml". Пакет содержит часть [Content_Types].xml, которая позволяет определить тип содержимого всех частей документа в пакете. Набор явных связей для пакета или части содержится в части связей с расширением .rels.

Текстовые документы описываются с помощью разметки WordprocessingML. Дополнительные сведения см. в разделе Работа с документами WordprocessingML (Open XML SDK). Документ WordprocessingML состоит из набора историй, где каждая история — это одно из следующих:

основной документ (единственная обязательная история);

верхний и нижний колонтитулы;

Презентации описываются с помощью разметки PresentationML. Дополнительные сведения см. в разделе Работа с документами PresentationML (Open XML SDK). Пакет презентации может содержать следующие части документа:

Листы книги описываются с помощью разметки SpreadsheetML. Дополнительные сведения см. в разделе Работа с документами SpreadsheetML (Open XML SDK). Пакет книги может содержать следующие элементы:

часть книги (обязательная);

один или несколько листов;

Пакет Open XML SDK 1.0

Версия 1 пакета Open XML SDK упрощает управление пакетами Open XML. API-интерфейс Open XML SDK позволяет выполнять многие распространенные задачи, которые обычно выполняются с пакетами Open XML, поэтому сложные операции можно реализовать несколькими строками кода. Вот некоторые распространенные задачи:

Поиск — несколькими строками кода можно выполнить поиск произвольных данных в коллекции листов Excel 2007.

Сборка документов — вы можете создавать документы, объединяя части существующих документов программными средствами. Например, можно извлечь слайды из различных презентаций PowerPoint 2007 и создать из них одну презентацию.

Проверка — несколькими строками кода можно проверить части документа в пакете или весь пакет на соответствие схеме.

Обновление данных — с помощью объектной модели Open XML можно легко изменить данные в нескольких пакетах.

Конфиденциальность — несколькими строками кода можно удалить примечания или другие личные данные из документа перед его публикацией.

Пакет Open XML SDK 2.0 для Microsoft Office

Пакет Open XML SDK 2.0 для Microsoft Office расширил поддержку строго типизированных классов от классов частей, которые представлены в версии 1.0, до XML-содержимого каждой части. Все функции, доступные в версии 1.0, по-прежнему поддерживаются. Версия 2.0 позволяет программно обрабатывать XML-содержимое частей. Пакет SDK поддерживает программирование в стиле LINQ to XML, который упрощает написание кода для работы с XML-содержимым, по сравнению с традиционной моделью программирования W3C XML DOM.

Пакет SDK поддерживает следующие распространенные задачи и сценарии:

Строго типизированные классы и объекты — вместо использования общих функций XML для обработки данных XML, для чего требуется помнить имена всех элементов, атрибутов и значений, а также пространства имен, для решения тех же задач можно использовать пакет Open XML SDK, просто обрабатывая объекты, представляющие элементы, атрибуты и значения. Все типы схемы представлены как строго типизированные классы среды выполнения CLR, а все значения атрибутов представлены как перечисления.

Формирование, поиск и обработка содержимого — технология LINQ встроена непосредственно в SDK. Таким образом вы можете создавать функциональные конструкции и запросы с лямбда-выражениями непосредственно для объектов, представляющих элементы Open XML. Кроме того, пакет SDK позволяет легко обходить и обрабатывать содержимое, предоставляя поддержку коллекций объектов, например таблиц и абзацев.

Проверка — Open XML SDK 2.0 для Microsoft Office предоставляет возможности проверки, что позволяет проверять документы Open XML на соответствие различным вариантам формата Open XML.

Пакет Open XML SDK 2.5 для Office

Пакет SDK 2.5 Open XML предоставляет пространства имен и члены для поддержки Microsoft Office 2013. Open XML SDK 2.5 также может читать файлы в строгом формате ISO/IEC 29500. Строгий формат — это подмножество переходного формат, который не содержит устаревшие функции — это теоретически облегчает поддержку для новых разработчиков, поскольку формат более прост.

Пакет SDK поддерживает следующие распространенные задачи и сценарии:

Поддержка формата файлов Office 2013 Preview — кроме классов Open XML SDK 2.0 для Microsoft Office, Пакет SDK 2.5 Open XML предоставляет новые классы, которые позволяют создавать приложения для обработки расширений файлов Open XML новых компонентов Office 2013.

Исправления Open XML SDK 2.0 для Microsoft Office — в Пакет SDK 2.5 Open XML исправлены известные проблемы Open XML SDK 2.0 для Microsoft Office. К ним относятся потерянные пробелы в презентациях PowerPoint и проблема с настраиваемым пользовательским интерфейсом в документах Word, из-за которой указанный аргумент считался выходящим за допустимый диапазон.

Дополнительные сведения об этих и других новых возможностях Пакет SDK 2.5 Open XML см. в статье Новые возможности в Open XML SDK 2.5 для Office.

image1.jpg

Office Open XML, также известный как OpenXML или OOXML, представляет собой формат на основе XML для офисных документов, включая текстовые документы, электронные таблицы, презентации, а также диаграммы, фигуры и другой графический материал. Спецификация была разработана Microsoft и принята ECMA International в 2006 году. В июне 2014 года Microsoft выпустила Open XML SDK в open source. Сейчас исходники доступны на GitHub под лицензий MIT.

Проект достаточно маленький и предупреждений нашлось немного. Но выбор титульной картинки основывался как раз на результатах. Уж очень много бесполезных условных операторов в коде нашлось. Мне кажется, если отрефакторить все такие места в коде, то объём заметно сократится. Вследствие чего ещё и читаемость кода повысится.

Почему Word API, а не Open XML SDK

Как Вы могли догадаться из заголовка, я продолжил использовать Word API. У этого способа достаточно много минусов:

  • Старый неудобный API;
  • Должен быть установлен Microsoft Office;
  • Необходимость распространять дистрибутив с библиотеками Office;
  • Зависимость работы Word API от настроек локали системы;
  • Низкая скорость работы.

Перечисляя всё это, я снова задумался, почему я до сих пор этим пользуюсь…

Но нет, Word API мне пока нравится больше, и вот почему.

OOXML выглядит таким образом:


Где <w:r> (Word Run) — не предложение, и даже не слово, а любой фрагмент текста, имеющий атрибуты, отличные от соседних фрагментов текста.

Программируется это примерно таким кодом:


У документа специфичная внутренняя структура, и в коде нужно создавать те же самые элементы. У Open XML SDK, я считаю, недостаточно абстрактный уровень доступа к данным. Создание документа с помощью Word API будет более понятым и коротким. Особенно, когда дело дойдёт до таблиц и других сложных структур данных.

В свою очередь, Open XML SDK решает большой ряд задач. С ним можно создавать документы не только для Word, но и для Excel и PowerPoint. Наверное, для некоторых задач эта библиотека больше подходит, но я решил пока остаться на Word API. Полностью от него отказаться в любом случае не получится, т.к. для внутренних нужд мы разрабатываем плагин для Word, а там возможно использование только Word API.

Два значения для string

V3008 The '_rawOuterXml' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 164, 161. OpenXmlElement.cs 164


Тип string может иметь 2 типа значений: null и текстовое значение. Использовать текстовое значение определённо безопаснее, но оба подхода имеют права на существование. Вот в этом проекте значение null использовать неприемлемо и его перезаписывают на string.Empty… по крайней мере, так задумывалось. Но из-за ошибки в RawOuterXml всё же можно записать null, а потом обратиться к этому полю, получив NullReferenceException.

V3022 Expression 'namespaceUri != null' is always true. OpenXmlElement.cs 497


В этом фрагменте используется тот же самой подход, автор кода не сделал какую-то серьёзную ошибку, но всё ещё чувствуется запах неудачного рефакторинга. Скорее всего, одну проверку тут можно удалить, что уменьшит ширину кода, а, следовательно, повысит его читаемость.

Про компактность кода

image2.jpg

V3009 It's odd that this method always returns one and the same value of '".xml"'. CustomXmlPartTypeInfo.cs 31


Не знаю, имеет ли место тут какая-нибудь опечатка или просто автор кода написал "красивый" код по его мнению. Я уверен, что нет смысла возвращать из функции столько однотипных значений и код можно сильно сократить.

Это не единственное такое место. Вот ещё парочка таких предупреждений:

  • V3009 It's odd that this method always returns one and the same value of '".xml"'. CustomPropertyPartTypeInfo.cs 25
  • V3009 It's odd that this method always returns one and the same value of '".bin"'. EmbeddedControlPersistenceBinaryDataPartTypeInfo.cs 22

V3139 Two or more case-branches perform the same actions. OpenXmlPartReader.cs 560


К этому коду возникает меньше вопросов. Скорее всего, идентичные кейсы можно объединить и код станет короче и очевиднее.

Ещё несколько таких мест:

  • V3139 Two or more case-branches perform the same actions. OpenXmlMiscNode.cs 312
  • V3139 Two or more case-branches perform the same actions. CustomPropertyPartTypeInfo.cs 30
  • V3139 Two or more case-branches perform the same actions. CustomXmlPartTypeInfo.cs 15
  • V3139 Two or more case-branches perform the same actions. OpenXmlElement.cs 1803

Те самые Always true/false

Настало время привести примеры кода, которые определили мой выбор титульной картинки.

Предупреждение 1

V3022 Expression 'Complete()' is always false. ParticleCollection.cs 243


Свойство IsComplete используется 2 раза, и по коду легко понять, что его значение не изменится. Таким образом, в конце функции можно просто возвращать второе значение тернарного оператора – true.

Предупреждение 2

V3022 Expression '_elementStack.Count > 0' is always true. OpenXmlDomReader.cs 501


Очевидно, что если в стеке_elementStack не 0 элементов, то их больше. Код можно сократить как минимум на 8 строк.

Предупреждение 3

V3022 Expression 'rootElement == null' is always false. OpenXmlPartReader.cs 746


Функция CreateElement не может вернуть null. Если в компании было принято правило писать методы для создания xml-нод, которые либо возвращают валидный объект, либо кидают исключение, то пользователям таких функций можно не злоупотреблять дополнительными проверками.

Предупреждение 4

V3022 Expression 'nameProvider' is always not null. The operator '?.' is excessive. OpenXmlSimpleTypeExtensions.cs 50


Оператор is имеет такой паттерн:


Если результат выражения is будет true, то в varname будет записана ненулевая ссылка, так что дополнительная её проверка на null является лишней.

Предупреждение 5

V3022 Expression 'extension == ".xlsx" || extension == ".xlsm"' is always false. PresentationDocument.cs 246


Интересный код получился. Сначала автор отсеял все документы с расширениями не .pptx, .pptm, .potx и .potm, а потом решил для перестраховки проверить, что среди них нет .xlsx и .xlsm. Функция PresentationDocument – определённо жертва рефакторинга.

Предупреждение 7

V3022 Expression 'OpenSettings.MarkupCompatibilityProcessSettings == null' is always false. OpenXmlPackage.cs 661


Свойство MarkupCompatibilityProcessSettings никогда не возвращает null. Если в геттере выясняется, что поле класса имеет значение null, то объект перезаписывается на новый. Ещё обратите внимание, что это не рекурсивный вызов одного свойства, а это одноимённые свойства из разных классов. Возможно, некоторая путаница и привела к написанию лишних проверок.

Остальные предупреждения

Предупреждение 1

V3080 Possible null dereference. Consider inspecting 'previousSibling'. OpenXmlCompositeElement.cs 380


А вот пример, где дополнительной проверки как раз не хватает. Метод PreviousSibling как раз может вернуть значение null, а результат этой функции сразу используется без проверки.

Ещё 2 опасных места:

  • V3080 Possible null dereference. Consider inspecting 'prevNode'. OpenXmlCompositeElement.cs 489
  • V3080 Possible null dereference. Consider inspecting 'prevNode'. OpenXmlCompositeElement.cs 497

V3093 The '&' operator evaluates both operands. Perhaps a short-circuit '&&' operator should be used instead. UniqueAttributeValueConstraint.cs 60


Некоторые любят применять оператор '&' к логическим выражениям там, где не надо. В случае этого оператора сначала вычисляется второй операнд, независимо от результата первого. Здесь это не сильно серьёзная ошибка, но такой неаккуратный код после рефакторинга может приводить и к потенциальным исключениям NullReferenceException.

Предупреждение 3

V3097 Possible exception: type marked by [Serializable] contains non-serializable members not marked by [NonSerialized]. OpenXmlPackageValidationEventArgs.cs 15


Сериализация класса OpenXmlPackageValidationEventArgs может стать неудачной из-за того, что одно из свойств забыли пометить несериализуемым. Либо необходимо доработать возвращаемый тип этого свойства до сериализуемого, иначе может возникать исключение в рантайме.

Заключение

Мы в компании любим проекты и технологии Microsoft. В разделе, где мы перечисляем Open Source проекты, проверенные с помощью PVS-Studio, мы даже выделили для Microsoft отдельный раздел. Там уже накопился 21 проект, про которые написано 26 статей. Это 27-я.

Уверен, Вас интересует, есть ли среди наших клиентов Microsoft. Ответ – да! Но не будем забывать, что это огромная корпорация, ведущая разработку по всему миру. Определённо есть подразделения, которые уже используют PVS-Studio в своих проектах, но тех, которые не используют, ещё больше! И наш опыт работы с открытыми проектами показывает, что им явно не хватает хорошего инструмента для поиска ошибок ;).



Введение

Office Open XML, также известный как OpenXML или OOXML, представляет собой формат на основе XML для офисных документов, включая текстовые документы, электронные таблицы, презентации, а также диаграммы, фигуры и другой графический материал. В июне 2014 года Microsoft выпустила исходный код Open XML SDK на GitHub для работы с таким форматом.

У этой библиотеки есть серьёзные преимущества:

не требует установки Microsoft Office,

высокая скорость работы,

открытый исходный код.

Без минусов тоже не обошлось:

Эти минусы определённо дополняют друг друга. Собственно, это и стало причиной создания этого материала.

Боль разработчиков Office

Основы

Прежде чем приступить к разбору примеров, стоит понять, с чем вообще работают эти две библиотеки и в чём состоит разница их подходов.

Word документ — это набор запакованных xml-документов. Все элементы структурированы под тегами.

Например, параграф внутри документа будет выглядеть примерно вот так:

Сборка Interop.Word немного абстрагируется от этой структуры и часто работает с некоторым участком – Range – документа. А Open XML SDK идёт по пути отражения внутренней структуры документа в самом коде. Параграфы <w:p>, участки текста <w:t> и всё остальное становятся объектами в самом коде. Если вы не создадите тело документа, параграф и других обязательных "родителей", то и добавлять текст будет некуда.


На скриншоте как раз изображена внутренняя структура основного файла для документа Word – document.xml. Этот файл содержит само наполнение документа.

Скриншот сделан в очень нужной для работы с Open XML утилите Open XML SDK 2.5 Productivity Tool. К моменту написания статьи эта утилита была удалена с сайта Microsoft, а в репозитории Open-XML-SDK добавлена ссылка на некий DocxToSource, который должен стать заменой устаревшего Productivity Tool. Однако эта замена всё ещё является прототипом, поэтому пока лучше постараться найти старый добрый Productivity Tool. Старая утилита позволяет просмотреть строение документа, познакомиться с автогенерированным кодом.


Также она позволяет сравнить два разных документа (и код для их создания, и их внутреннее строение).


Примеры

Для Interop.Word во всей статье примем такой псевдоним для удобства чтения:

Также для упрощения будем называть Open XML SDK просто Open XML.

Создание документа

Interop.Word:

Тут всё достаточно просто, но всё равно есть свои подводные камни. При работе с Interop мы взаимодействуем не просто с некоторым объектом в памяти, а с COM-объектом. Поэтому возникает необходимость завершать все процессы после окончания работы программы. Эта проблема не раз поднималась на Stack Overflow (1, 2), и ей предложено множество разных решений.

Есть решение с участием Marshal Class, являющимся частью InteropServices.

Однако в таком случае можно упустить какие-нибудь процессы.

Есть более надёжный вариант с обращением к GC:

Эти методы надо вызвать после того, как вся работа с COM-объектами будет завершена.

Если не завершить процессы, то при активном дебаге можно устроить себе такую ситуацию:


Но даже если в коде присутствует закрытие процессов после окончания работы, при прерывании программы вручную или её падении процесс останется запущенным. Такого недостатка нет при создании и работе с документом через Open XML.

Open XML:

Обратите внимание на добавление SectionProperties, они понадобятся нам позже.

Добавление параграфа

Interop.Word

Текст также можно сделать жирным или курсивным через параметр Font:

Изменить размер шрифта можно через:

Выравнивание текста выполняется через ParagraphFormat.Alignment:

Open XML:

В случае с Open XML жирным или курсивным текст можно сделать через:

Изменение размера шрифта в этом случае немного неинтуитивно, но согласуется с общей логикой работы с Open XML:

Важно перед этим не забыть добавить к параграфу свойства:

Вставка заголовка

Предположим, что нам нужно вписать в документ заголовок. В случае Interop.Word нужно всего лишь небольшое дополнение к вставке текста, чтобы получить заголовок:

Interop.Word:

В этом случае сначала задаём Range для записи нового текста и присваиваем ему стиль Heading 1.

Open XML:

Тут, казалось бы, всё очень похоже. Аналогично добавляем параграф и в случае с Open XML организуем нужную иерархию объектов.

Однако на самом деле в случае с Open XML коварным оказывается добавление стиля. Interop.Word работает с реальным полноценным документом, как если бы вы запустили Word и нажали создать. А вот Open XML работает только с тем, что было создано. И если вы добавляете текст документу, созданному через Open XML, а не через Interop.Word, то в нём будут отсутствовать, например, стили. Соответственно, никакого стиля Heading1 в таком документе не будет. Его нужно сначала добавить.

Удобнее всего добавлять нужный стиль при создании документа. Есть два варианта: перенести стили из готового Word-документа или добавить эти стили вручную.

В первом случае в документе, из которого будет браться стиль, нужно обязательно применить искомый стиль. Сам перенос требует достаточно много кода, благо, в официальной документации есть мануал на эту тему.

Для второго варианта нам поможет Productivity Tool для Open XML, упоминавшийся ранее. Чтобы получить код, нужный для добавления желаемого стиля, создаём чистый документ Word, используем в нём нужный стиль и "скармливаем" этот документ утилите. Далее через использование кнопки Reflect Code на /word/styles.xml в структуре документа мы получим реализацию метода GeneratePartContent. В нём мы ищем реализацию нужного стиля и всё, что с ним связано, включая StyleParagraphProperties, StyleRunProperties и т.д.

Для стиля Heading 1 нужный нам автосгенерированный код будет выглядеть примерно так:

Чтобы добавить перенесённый стиль к генерируемому документу, нужно создать набор стилей Styles и добавить стиль к набору. Далее к документу нужно добавить StyleDefinitionsPart и присвоить группу стилей. Выглядеть это будет вот так:

У себя мы решили использовать вариант с шаблонным документом, чтобы в будущем при появлении необходимости в каком-либо стиле нужно было лишь использовать его в шаблоне и работать с ним в коде вместо того, чтобы каждый раз рыться в ProductivityTool и копировать себе полотна кода с объявлением нужного стиля.

Смена ориентации страницы

Для нашего отчёта нам нужна была именно ландшафтная ориентация страницы.

Interop.Word:

У документа получаем нужный Range (страниц или всего документа) и задаём ландшафтную ориентацию.

Open XML:

C Open XML в этом случае всё не настолько абстрактно, как хотелось бы. Если вы инициализируете в PageSize только поле Orient, то ничего не изменится. Width и Height тоже нужно менять.

Гиперссылки

Interop.Word:

Тут всё просто: как обычно, получаем нужный Range и добавляем гиперссылку. У метода Add много параметров, и можно сконструировать более сложную ссылку.

Open XML:

Из существенных отличий тут то, что url нужно сначала обернуть в Uri и создать связь url с гиперссылкой через AddHyperlinkRelationship. Потом при создании самой гиперссылки, нужно присвоить полю Id новой гиперссылки Id созданной ранее связи.

Картинки

Interop.Word:

Тут всё достаточно просто, а с Open XML всё оказалось крайне сложно.

Open XML:

Для добавления картинки необходимо соблюсти сложную иерархию объектов с определёнными параметрами. Хорошо, что есть документация на этот счёт. Поэтому пропустим код, требуемый для добавления картинки в этой статье. Разберём ещё один момент, который почему-то не упоминается в документации. Можете заметить, что в том коде нигде не передаётся размер картинки. Фиксируется её размер тут:

Если использовать этот код, то вместо нормальной картинки, будет вставлено малюсенькое изображение. Его реальный размер никак не изменится, но при отображении оно будет отмасштабировано до таких размеров:


Дело в том, что масштаб отображения картинки здесь завязан на такую вещь, как EMU (English Metric Units).

Для того чтобы передавать методу добавления картинки привычные размеры в пикселях, потребуется следующее преобразование:

Тут мы получаем количество EMU на пиксель, приняв значение PPI за 96, и умножаем полученное значение на нужное количество пикселей для ширины и высоты. В итоге у наc есть нужная нам ширина и высота в EMU. Их мы и передаём как Cx и Cy для Extent и Extents:

Таблицы

Interop.Word:

Генерация таблицы через Interop.Word достаточно прямолинейна. Разберём пример, как можно было бы вставить таблицу из квадратной матрицы строк.

Параметры метода AddDefaultTableBehavior и AutoFitBehavior — как видно из их названия, отвечают за поведение таблицы при необходимости изменения размера под содержимое ячеек. Им присваиваются значения перечислений WdDefaultTableBehavior и WdAutoFitBehavior соответственно. Сам метод Add создаёт в документе таблицу с нужными нам параметрами.

Стиль к таблице можно применить следующим образом:

Также для красивого выделения первого столбика, если он является заголовочным, можно присвоить true полю oTable.ApplyStyleFirstColumn.

Расстояние между параграфами текста контролируется через oTable.Range.ParagraphFormat.SpaceAfter. Для компактного отображения таблицы можно использовать

Также можно устанавливать тип написания текста к строкам или колонкам:

Используя эти возможности, можно получить вот такую таблицу:


Open XML:

При создании таблицы с нуля с Open XML стоит помнить о том, что никаких ячеек или строк к моменту ввода данных не существует. Их нужно сначала создать, соблюдая внутреннюю иерархию.

Поэтому при проходе по матрице мы для каждой строки создаём TableRow, а потом для каждого элемента в строке создаём TableCell, куда добавляем новые Paragraph, Run и Text с соответствующим значением из матрицы. TableCellProperties лучше также добавить сразу, чем потом при дальнейшей работе с таблицей наткнуться на System.NullReferenceException при попытке добавить свойство ячейке.

Если мы не зададим в TableProperties ни стиля, ни Borders, то таблица будет выглядеть вот так


Границы таблицы формируются через TableBorders.

Перечисление BorderValues здесь задаёт стиль границ.

TableBorders нужно добавить к TableProperties через

Границы таблицы можно не задавать, если ей будет присвоен какой-нибудь стиль. Главное не забыть, что стиль сначала нужно добавить к документу.

Задаётся стиль достаточно просто:

Его так же, как и границы, нужно добавить к TableProperties:

Для того чтобы таблица заняла всю ширину страницы можно использовать TableWidth заданную следующим образом:

Значение 5000 тут взято "не из воздуха". Тип единицы ширины здесь мы задаём TableWidthUnitValues.Pct – единицы ширины в одну пятидесятую процента страницы или 0,02%. В итоге пять тысяч Pct это 100% ширины страницы.

Этот параметр добавляется к TableProperties аналогичным образом:

Важный момент: TableProperties должны быть добавлены к таблице до самих данных для того, чтобы они работали корректно. Их можно добавить и после других объектов, но тогда уже стоит использовать

Раскраска таблиц

Для формирования нашего отчёта нам нужно было раскрасить ячейки в некоторых таблицах документа.

Interop.Word:

где oTable – это созданная нами ранее таблица, i и j — это индексы нужной ячейки. Присваиваемое значение – перечисление WdColor.

Open XML:

где tc – это TableCell, с которой идёт работа. Полю Fill присваивается строка с Hex-значением цвета.

Разрыв страницы

В нашем случае отчёт генерируется последовательно, поэтому разрыв страницы нужно было вставить после последнего добавленного текста.

Interop.Word:

Open XML:

Тип разрыва меняется через перечисление BreakValues.

Footer/Header

Также нам нужны были футеры/хедеры в документе.

Interop.Word:

Через headerRange.Font можно поменять параметры текста, например размер, шрифт, цвет и т.д. А headerRange.ParagraphFormat.Alignment, как следует из названия, задаёт выравнивание текста. Это поле принимает значения WdParagraphAlignment.

Open XML:

Тут сложность состоит в том, что футер/хэдер сам по себе хранится в отдельном .xml файлике. Поэтому нам нужно связать хэдер/футер с содержанием документа через SectionProperties.

Если нужно, чтобы текст перезаписывался на новый при вызове метода добавления хедера, то вместо

Для футера нужно будет передать mainDocumentPart.FooterParts.

Заключение

Описанные методы работы с Open XML SDK можно собрать в библиотеку классов для внутреннего использования в компании, что мы и сделали. Создание Word документов стало даже удобнее, чем было с Word Interop API.

Здесь может возникнуть закономерный вопрос, есть ли готовые библиотеки на основе Open XML SDK для упрощённой работы с документами? Ответ – однозначно да. Но, к сожалению, поддержка таких библиотек быстро прекращается. Истории создания таких проектов все одинаковые: программисты начинают работать с Word, осознают неудобство существующей инфраструктуры, дорабатывают её — и некоторые библиотеки публикуются на GitHub. Даже если удастся найти относительно свежую версию подобной библиотеки, то, скорее всего, она была реализована под задачи конкретного проекта, и в вашем проекте всё равно будет неудобной в использовании. Плюс появится риск остаться с неподдерживаемой библиотекой.

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Victoria Khanieva, Svyatoslav Razmyslov. Tutorial: how to port a project from Interop Word API to Open XML SDK.

Читайте также: