Отправляет email-рассылки с помощью сервиса Sendsay

Всё о документообороте

  Все выпуски  

Запись блога "Open Packaging Conventions #2. Собираем MS Word документ руками" от Михаил Романов


Все о документообороте

Сайт рассылки
 



Запись блога "Open Packaging Conventions #2. Собираем MS Word документ руками" от Михаил Романов
2014-11-18 19:19 Михаил Романов

imageВ предыдущей статье я постарался “просто и доступно” Улыбкарассказать о том, что такое Open Package Convention (или иначе говоря, как устроены изнутри документы MS Office 2007+).

Сегодня мы в качестве практики создадим пару документов для MS Word, не используя никаких специальных инструментов (за исключением XML-редактора и Zip-архиватора).

Сразу же оговорюсь, что мы не будем сильно вдаваться в особенности разметки документов Word (хотя, конечно же, минимальные представления о ней все же понадобятся, но всё необходимое для понимания я постараюсь рассказать по мере развития статьи)! Наша задача: увидеть как строятся реальные пакеты на основе OPC – что такое компоненты, связи и как они хранятся.

Документ #1 – простой текст

Если попробовать заглянуть внутрь готового Word-документа, созданного в Office, можно легко прийти в ужас от обилия различных компонент непонятного формата назначения.

В реальности структура самого простого рабочего документа (такого, который сможет открыть и показать Word) включает всего 3 элемента:

●   главный компонент, который содержит разметку всего документа

●   1 компонент связи (который содержит связь между пакетом и главным компонентом

●   описание типов (файл [Content_Types].xml)

Примерно так:

image

Давайте теперь создадим пустую папку, которая будет представлять содержимое всего пакета, и будем последовательно её заполнять.

Главный компонент документа. Создадим в нашей папке файл 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. Содержать этот файл будет всего одну связь:

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship
        Id="rId1"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
        Target="main.xml" />
</Relationships>

Описание типов. По большому счету, в нашем примере используется всего 2 типа контента: в компоненте с основным содержимым документа и в компоненте связи. Однако, хотя мы дали главному компоненту “расширение” .xml, его тип содержимого по стандарту OpenXML должен быть не просто application/xml, поэтому мы опишем 3 типа контента: для всех компонентов связей, для “некого произвольного xml” и явно для компонента /main.xml.

Итак, создадим в нашей папке файл [Content_Types].xml следующего содержания:

<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
        <Default Extension="rels"
            ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
        <Default Extension="xml"
            ContentType="application/xml"/>
        <Override PartName="/main.xml"
            ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
</Types>

Итак, содержимое нашей папки составляют 3 файла:

●   \_rels\.rels

●   \[Content_Types].xml

●   \main.xml

Осталось упаковать их в отдельный архив, переименовать архив в, например, result.docx, и открыть полученный файл в Word. Наш результат будет:

image

Давайте теперь усложним пример, добавив в документ изображение.

Документ #2 – тот же текст и картинка

Какие изменения нам потребуется внести в предыдущий пример? Вот они:

●   добавить компонент с изображением и дополнить описание типов содержимого

●   создать связь от главного компонента к компоненту с изображением (а это значит, что добавить еще один компонент связей)

●   дополнить разметку самого документа (указать место и параметры вставляемой картинки)

Структура нашего пакета приобретет во такой вид:

image

В принципе, ничего сверхъестественного, поэтому приступим.

Компонент картинки и тип содержимого для него. Для добавления компонента просто скопируем готовый файл с картинкой в папку, к остальным компонентам (пусть это будет файл cat.jpeg).

После этого обновим содержимое файла типов содержимого ([Content_Types].xml):

<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
        <Default Extension="jpeg"
            ContentType="image/jpeg"/>
        <Default Extension="rels"
            ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
        <Default Extension="xml"
            ContentType="application/xml"/>
        <Override PartName="/main.xml"
            ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
</Types>

Связь от /main.xml к /cat.jpeg. Так как мы создаем связь от компонента /main.xml, имя компонента связей для него будет /_rels/main.xml.rels, а значит создадим в папке _rels еще один файл с именем main.xml.rels и содержащем описание 1 связи:

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship
        Id="rId1"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
        Target="cat.jpeg" />
</Relationships>

Осталось самое сложное – поправить разметку самого документа.

Разметка главного компонента. Вообще, надо признать, что разметка документов 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:

image

Вот и все.

P.S. Для желающих продолжить эксперименты – все исходные файлы, а также результаты можно найти на Codeplex в проекте https://msosamples.codeplex.com (здесь и далее я планирую размещать все приводимые примеры). Прямая ссылка на нужную папку.


 



 
 
С пожеланиями успехов,
Михаил Кузьмин
 

В избранное