Файлы MS Office "изнутри". Open Packaging Conventions. Базовые принципы. Компоненты и связи
Сегодняшним постом я хочу начать серию материалов. В ней я планирую немного поговорить о том, что представляют собой файлы MS Office “изнутри”, а также об инструментах (утилитах и библиотеках) для их создания, изучения, изменения, …
Сегодняшним постом я хочу начать еще одну серию. В ней я планирую немного поговорить о том, что представляют собой файлы MS Office “изнутри”, а также об инструментах (утилитах и библиотеках) для их создания, изучения, изменения, …
Прежде чем перейти к содержательной части некоторый предваряющий disclaimer (традиционно ):
● Я в основном буду касаться современных офисных форматов, тех что появились в редакции Office 2007. Их еще называют XML-based форматами, в противовес старым бинарным (и это закрепилось в расширении файлов: docx, pptx, xlsx, … – в противовес doc, ppt, xls, …), ну или просто Open XML
● Некоторая часть статей (по крайней мере в самом начале) будет основана на материалах Open XML Developer Workshop (контент и видео), который вел Doug Mahugh. Если вам не хочется ждать моих статей рекомендую обратиться к этим материалам
● Еще одним хорошим подспорьем для изучающих Open XML будет книга Воутер Ван Вугт. OpenXML. Кратко и доступно. Ранее она в электронном виде была доступна в блоге евангелиста Microsoft Владимира Габриеля, но теперь – увы. Так что, если вам интересно и не хочется тратить время на поиск, можете взять здесь.
Вроде бы все. Можно приступать.
Что такое Open Packaging Conventions?
В двух словах, это формат контейнеров, поддерживающих хранение как структурированных (XML), так и неструктурированных компонентов (картинки, видео, бинарные компоненты, …) в одном файле.
Краткая но довольно информативная статья об OPC есть на wikipedia.
Что можно сказать в общем об этом стандарте/формате? Я бы выделил такие моменты:
● Формальное описание является частью ECMA-376. Office Open XML File Formats, более конкретно – второй частью Part 2 — Open Packaging Conventions.
● Сам стандарт описывает только структуру хранения и самые общие метаданные (типа автора, даты,…) поэтому потенциально в таком контейнере можно хранить практически что угодно.
Например, вот несколько форматов, основанных на OPC от самого Microsoft:
o .docx, pptx, xlsx, .vsdx – форматы Word, Power Point, Excel и Visio
o .xps (.oxps) – формат “электронной бумаги” или формат c фиксированной разметкой, предназначенный для передачи документов без искажения форматирования (в чем-то аналог PDF).
o .vsix – формат расширений Visual Studio, начиная с версии 2010
o .cspkg – формат пакетов для Windows Azure Cloud Services
o .appx – формат пакетов приложений Windows Store (для Windows 8)
Что представляют собой контейнеры в OPC?
Тут нужно сделать одну существенную оговорку: сам стандарт разбивает описание контейнеров на 2 части: абстрактную модель (которая описывает из каких элементов состоят контейнеры, но ни слова не говорит о том как это должно храниться физически) и физический формат пакета, т.е. конкретную реализацию.
Т.е. в чистой теории, контейнер в OPC может храниться единый файл, а может, например, как набор отдельных ресурсов на Web-сервере. Но (!) на текущий момент определена только 1 реализация – в виде единого файла ZIP-архива.
Структура контейнеров в OPC
Вообще говоря, концептуальная схема пакетов в Open Packaging Conventions очень проста, она включает в себя всего два элемента:
● компоненты (parts), которые собственно и содержат хранящийся контент (любой: xml, image, video, …)
● отношения (relationships), которые определяют
o предназначение (смысл/семантику) каждой части
o отношения между частями, а также между частями и пакетом целиком
Компоненты
Как уже было сказано выше компонент в OPC это и есть основная единица хранения контента. Каждый компонент характеризуется 2-я составляющими: именем и типом содержимого.
Имя компонента состоит из набора сегментов, начинающихся с прямого слэша (“/”), вот несколько примеров:
● /hello/world/doc.xml
● /docProps/app.xml
● /image4.png
В спецификации приведены более формальные правила построения имен, из которых я укажу только основные (на мой взгляд):
● все имена должны начинаться с прямого слэша (“/”) и не должны им заканчиваться
● имя недолжно содержать пустых сегментов (т.е. /images//image1.jpg – неправильное имя)
● сегменты могут состоять из букв, цифр и знаков «!«, «$«, «&«, «‘«, «(«, «)«, «*«, «+«, «,«, «;«, «=«, «-«, «.«, «_«, «~«, «:«, «@»
● ни одно имя компонента не должно строиться как имя уже существующего компонента + новый сегмент. Т.е. если есть компонент с именем /abc/abc, то компонент с именем /abc/abc/a существовать не может, зато вполне может существовать компонент с именем /abc/abcde
● имена могут записываться Unicode-символами или использовать кодирование в виде /a/%D1%86.xml
Тип содержимого компонента задается в соответствии с RFC 2616 (раздел Media Types) т.е. в виде <type>/<subtype>:
● application/xml
● image/jpeg
● application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml
Связи
Любой компонент в пакете (а также сам пакет) может ссылаться на другие компоненты или некоторые ресурсы за пределами пакета. Для представления этих ссылок введен специальный механизм связей. По большому счету, связи позволяют решить 2 задачи:
● получить список связанных с компонентом ресурсов, без необходимости анализировать его содержимое (которое может быть очень большим, иметь разную структуру, быть зашифрованным или вообще не поддерживать хранение ссылок)
● поменять набор связей компонента, не меняя его содержимого (которое может быть, например, зашифровано или защищено цифровой подписью)
Создавая свой пакет вы, конечно же, можете не использовать связи. Вместо этого везде в коде использовать фиксированные имена компонент, а где нужны списки связанных ресурсов, ссылаться на них прямо из самих компонент. Однако, рекомендации “лучших собаководов” все же советуют использовать связи везде, где это возможно.
Информация о связях для каждого компонента (а также самого пакета), хранится в специальных компонентах связей (relationships parts) тип содержимого которых application/vnd.openxmlformats-package.relationships+xml
Имена компонентов связи строятся из имени исходных компонент, к которым:
● добавляется предпоследний сегмент с именем _rels
● дописывается “расширение” .rels
Связи самого пакета хранятся в специальном компоненте с именем /_rels/.rels
Например, если в пакете у нас есть компонент с именем /document/mainPart.xml и два связанных компонента с картинками (пусть их мена будут /images/image1.png и /images/image2.jpeg), то пакет для них будет иметь следующую структуру:
Содержимое компонента связи представляет собой XML следующего формата:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="https://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1"
Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
Target="styles.xml" />
<Relationship Id="rId2"
Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
Target="theme/theme1.xml" />
<Relationship Id="rId3"
Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"
Target="fontTable.xml" />
<Relationship Id="rId4"
Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
Target="file:///C:\Users\Public\Pictures\Sample%20Pictures\Desert.jpg"
TargetMode="External" />
</Relationships>
Как уже наверняка понятно из приведенного фрагмента, каждый тэг <Relationship> определяет одну связь. Его атрибуты:
Id |
Идентификатор связи. На него ссылаются из содержимого компонент, когда необходимо использовать конкретную связь. |
Type |
Тип связи. По сути дела тип указывает семантику связи. Например, две разных связи могут указывать на 2 компонента типа image/jpeg, но одно изображение будет картинкой в тексте документа, а второе – миниатюрой (thumbnail) всей страницы целиком. |
TargetMode |
(Необязательный) Принимает одно из возможных значений: · Internal (значение по умолчанию) – указывает, что связь ссылается на компонент пакета · External – связь указывает на ресурс за пределами пакета |
Target |
Адрес ресурса или компонента на который ссылается связь |
Важный момент: для обращения к компонентам и внешним ресурсам можно использовать как абсолютные адреса (для компонент это будет их полное имя), так и относительные. В последнем случае полное имя компоненты рассматривается как путь в файловой системе, каждый сегмент, кроме последнего – имя “папки”, а последний – имя “файла”. Вот несколько примеров такой адресации:
Имя исходного компонента |
Относительный адрес |
Результирующий адрес |
/mydoc/markup/page.xml |
picture.jpg |
/mydoc/markup/picture.jpg |
/mydoc/markup/page.xml |
images/picture.jpg |
/mydoc/markup/images/picture.jpg |
/mydoc/markup/page.xml |
./picture.jpg |
/mydoc/markup/picture.jpg |
/mydoc/markup/page.xml |
../picture.jpg |
/mydoc/picture.jpg |
/mydoc/markup/page.xml |
/images/picture.jpg |
/mydoc/images/picture.jpg |
/ |
images/picture.jpg |
/images/picture.jpg |
Вот, по большому счету и все, что касается модели пакета в OPC. Осталось сказать несколько слов о физической реализации пакетов
Пакеты на основе ZIP-архивов
Как уже было сказано выше, в спецификации OPC определена только одна реализация пакетов – на основе ZIP архивов. Она достаточно проста, поэтому я приведу её обзорно:
● все компоненты, как обычные, так и компоненты связей, хранятся в виде одного или нескольких файлов внутри архива (при этом логически они все равно адресуются как единое целое)
● для хранения типа контента каждого компонента в архиве создается специальный файл с именем [Content_Types].xml
Внутри файла [Content_Types].xml хранится XML следующего вида:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="https://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="png" ContentType="image/png"/>
<Default Extension="jpeg" ContentType="image/jpeg"/>
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/word/document.xml"
ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
<Override PartName="/word/styles.xml"
ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
</Types>
Собственно, общая схема, я думаю, понятна и так: для описания типов используется два подхода:
● указание типа по расширению (тэг <Default>)
● явное указание типа для конкретного компонента (тэг <Override>)
Как заглянуть внутрь OPC-пакета?
Итак, надеюсь вас уже заинтриговало мое объяснение базовых принципов и вы уже жаждите приступить к практическому изучению (т.е. взять и разобрать по косточкам какой-нибудь офисный файл) .
Вот несколько способов как это можно сделать:
● Прямой (“рукопашный”) способ. Т.к. физическая реализация OPC есть ни что иное, как обычный ZIP-архив, то самый простой способ его изучить – распаковать и работать как с обычной папкой (ну или воспользоваться любимым архиватором).
o Плюс подхода – будете глубже понимать устройство.
o Минусы:
▪ Сложно отслеживать связи между компонентами (а именно они образуют структуру, а вовсе не “папки” архива)
▪ Довольно муторно редактировать, если захочется экспериментов (нужно добавлять файлы для компонентов, править файлы связей да еще и не забывать про указание типа контента, если он не стандартный)
● Open XML Package Editor Power Tool for Visual Studio 2010. Расширение для Visual Studio. Умеет открывать файлы в формате OPC, показывать и редактировать их логическую структуру (добавлять/удалять/редактировать компоненты и связи). Для редактирования содержимого компонент используется редакторы самой VS, что очень удобно для экспериментов (XML редактор в VS явно не самый плохой, особенно если в наличии есть хорошие XSD-описания).
o Минусы:
▪ Так и не нашел способа создать пакет с 0 (но это редко нужно, да и обходится созданием пакета вручную).
▪ Требует Visual Studio.
▪ Работает только в 2010 версии VS. Увы, для более новых версий студии пакет так и не обновился, хотя почти наверняка он заработает без доработок в любой последующей. А доработать установщик пакета руками не получается, т.к. это не обычный vsix
● Standalone приложение от Воутера Ван Вугта Open XML Package Explorer. По возможностям оно близко к предыдущему расширению для VS, но не требует ничего для установки, кроме .Net 3.0. У него даже есть встроенный редактор XML, правда уступающий редактору от VS. К сожалению, приложение давно не обновлялось имеет ряд неприятных ошибок… но пользоваться можно.
Пара слов в заключение
Как видите, стандарт OPC в своей основе довольно прост и функционален. Однако остались еще ряд нераскрытых тем. В частности мы не рассмотрели ряд возможностей, заложенных в формат OPC:
● базовые метаданные пакета (core properties)
● иконки пакета (thumbnails)
● цифровые подписи (digital signatures)
Ну и, конечно, мы еще ни слова не проговорили об API для работы с OPC пакетами.
Источник: Блог Михаила Романова.
Комментарии 0