В предыдущей
статье я постарался “просто и доступно” рассказать
о том, что такое Open Package Convention (или иначе говоря, как устроены
изнутри документы MS Office 2007+).
Сегодня мы в
качестве практики создадим пару документов для MS Word, не используя никаких
специальных инструментов (за исключением XML-редактора и Zip-архиватора).
Сразу же
оговорюсь, что мы не будем сильно вдаваться в особенности разметки документов
Word (хотя, конечно же, минимальные представления о ней все же понадобятся, но
всё необходимое для понимания я постараюсь рассказать по мере развития статьи)!
Наша задача: увидеть как строятся реальные пакеты на основе OPC – что такое
компоненты, связи и как они хранятся.
Документ #1 – простой текст
Если
попробовать заглянуть внутрь готового Word-документа, созданного в Office,
можно легко прийти в ужас от обилия различных компонент непонятного формата
назначения.
В реальности
структура самого простого рабочего документа (такого, который сможет открыть и
показать Word) включает всего 3 элемента:
● главный
компонент, который содержит разметку всего документа
● 1 компонент
связи (который содержит связь между пакетом и главным компонентом
● описание типов
(файл [Content_Types].xml)
Примерно так:
Давайте теперь
создадим пустую папку, которая будет представлять содержимое всего пакета, и
будем последовательно её заполнять.
Главный
компонент документа. Создадим в нашей папке файл main.xml
(в стандарте OpenXML нет жесткого требования к именованию компонент, поэтому мы
будем использовать свои имена, не такие как в Word).
Этот файл
будет представлять содержимое главного компонента (Main Document ы терминологии
стандарта). В лучших традициях книг по программированию зададим ему следующее
содержимое:
<document xmlns="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<body>
<!--
Структра тела документа включает в себя:
параграф (тэг <p>)
элемент текста с форматированием (тэг <r>)
собственно отображаемый текст (тэг <t>)
-->
<p>
<r>
<t>Hello, World!</t>
</r>
</p>
</body>
</document>
Компонент
связи.
Теперь мы должны указать что именно компонент /main.xml
содержит разметку документа. В OpenXML для этого используется механизм связей.
В нашем документе будет только одна связь – от пакета к главному компоненту
(главный компонент пока связей не имеет)
Как я писал в
предыдущей статье у компонента, который хранит связи всего пакета имя будет /_rels/.rels. Для
эмуляции такого имени (чтобы оно потом правильно создалось в конечном
ZIP-архиве) мы создадим подпапку
_rels, а в ней файл с именем .rels. Содержать этот файл будет всего одну
связь:
Описание
типов.
По большому счету, в нашем примере используется всего 2 типа контента: в
компоненте с основным содержимым документа и в компоненте связи. Однако, хотя
мы дали главному компоненту “расширение” .xml, его тип содержимого по стандарту
OpenXML должен быть не просто application/xml, поэтому мы опишем 3 типа
контента: для всех компонентов связей, для “некого произвольного xml” и явно
для компонента /main.xml.
Итак, создадим
в нашей папке файл [Content_Types].xml
следующего содержания:
Осталось
упаковать их в отдельный архив, переименовать архив в, например, result.docx, и открыть полученный файл в Word.
Наш результат будет:
Давайте теперь
усложним пример, добавив в документ изображение.
Документ #2 – тот же текст и картинка
Какие
изменения нам потребуется внести в предыдущий пример? Вот они:
● добавить
компонент с изображением и дополнить описание типов содержимого
● создать связь
от главного компонента к компоненту с изображением (а это значит, что добавить еще
один компонент связей)
● дополнить
разметку самого документа (указать место и параметры вставляемой картинки)
Структура
нашего пакета приобретет во такой вид:
В принципе,
ничего сверхъестественного, поэтому приступим.
Компонент
картинки и тип содержимого для него. Для добавления компонента просто скопируем
готовый файл с картинкой в папку, к остальным компонентам (пусть это будет файл
cat.jpeg).
После этого
обновим содержимое файла типов содержимого ([Content_Types].xml):
Связь
от /main.xml к /cat.jpeg. Так как мы создаем связь от компонента /main.xml, имя компонента связей для него будет
/_rels/main.xml.rels, а значит создадим в
папке _rels еще один файл с именем main.xml.rels
и содержащем описание 1 связи:
Осталось самое
сложное – поправить разметку самого документа.
Разметка
главного компонента. Вообще, надо признать, что разметка документов OpenXML местами
весьма далека от “интуитивно понятной” и это справедливо, в том числе для
описания изображений (в OpenXML используется единый подъязык для описания любых
изображений – DrawingML, у которого есть еще несколько внутренних диалектов:
для описания картинок, графиков, …).
Единственный
предварительный комментарий нужно дать по поводу размерности единиц… В OpenXML
используется специальная придуманная единица EMU (English Metric Unit) –
единица, которая позволяет относительно удобно переводить размеры из
метрической (метры/сантиметры) и американской (дюймы) систем единиц.
Соотношения следующие:
1 см
360000
EMU
1 дюйм
914400
EMU
Все, можно
оценивать (размеры областей вычислены на основе размеров картинки): Пример.
В нашей папке-пакете теперь
содержатся такие файлы:
§
\_rels\.rels
§
\_rels\main.xml.rels
§
\[Content_Types].xml
§
\cat.jpeg
§
\main.xml
Вновь собираем
все в один Zip-архив и открываем в Word:
Вот и все.
P.S. Для желающих продолжить
эксперименты – все исходные файлы, а также результаты можно найти на Codeplex в
проекте https://msosamples.codeplex.com
(здесь и далее я планирую размещать все приводимые примеры). Прямая ссылка
на нужную папку.