Word docxファイルの中身を探検する - Office Open XML ざっくり入門

「Word docxファイルはzipファイルとして展開できる」って、知ってましたか？

## シナリオ

あなたは、ドキュメント変換ツール「[Pandoc](http://pandoc.org/)」で、Markdownファイルからdocxファイルを生成したい、と考えます。

しかし、いろいろな都合で、docxファイルのフォーマットにかなり手を加える必要がある、とわかりました。
（たとえば、ルビ・脚注・図表など、単純なMarkdownの知識ではどうしようもないようなフォーマットを想定しましょう）

調べた結果、「[Pandocフィルタ](http://pandoc.org/filters.html)を書いて、docxファイルをいじればよい」とひとまず結論を出します。

さて……

- docxの中身ってどうなっているのでしょうか？
- どうやって、MS Word本体なしで、docxファイルをいじればよいのでしょうか？

下記では、前者の「docxの中身」についてざっくり話します。後者は割愛します。

## Office Open XMLとは

[Office Open XML (OOXML)](https://docs.microsoft.com/ja-jp/office/open-xml/open-xml-sdk)は、MS Officeのファイル（Office2007以降）の形式を定めている規格です。
雑に言えば「zip圧縮されたxmlファイル群＋アセットファイル（画像など）」という構成です。

厳密には、次の規格群によって定められています：

- [Open Packaging Conventions (OPC)](https://docs.microsoft.com/en-us/previous-versions/office/office-12//ee361919(v=office.12))
    - XMLを用いたパッケージの方法について定義
    - Officeファイルの他にも、[Microsoft系の各ファイル形式（appx/cspkg/xps/nupkgなど）で採用されているようです](https://ja.wikipedia.org/wiki/Open_Packaging_Conventions)。
- Office Open XML (OOXML)
    - MS Officeに限らず、一般的でオープンなオフィスファイルの仕様を定義
        - （ただしLibreOfficeと比べると、Microsoftの意向がだいぶ入るので、本当の意味での「オープン」性は懐疑的？）
    - [ECMA-376, Second Edition](http://www.ecma-international.org/publications/standards/Ecma-376.htm) および [ISO/IEC 29500](https://www.iso.org/standard/51463.html)

さらに、MS Officeの各ソフト（Word、Excel、PowerPoint）によって、それぞれ具体的な規格が定められています：

- WordprocessingML (Word docxに対応)
- SpreadsheetML (Excel xlsxに対応)
- PresentationML (PowerPoint pptxに対応)

## docxファイルの中身

とにかく、docxファイルを調達しましょう。
便宜上、ここではPandocがデフォルトで利用する `reference.docx` というファイルを使います。

```
$ pandoc --print-default-data-file=reference.docx > reference.docx
```

まず、**docxファイルはzipアーカイブです**。
docxファイルをzipファイルと見なせば、展開ができます。

ひとまず、中身をざっくり見てみましょう。

```
$ unzip -l reference.docx
Archive:  reference.docx
  Length      Date    Time    Name
---------  ---------- -----   ----
     1830  02-22-2019 07:00   [Content_Types].xml
      724  02-22-2019 07:00   _rels/.rels
      724  02-22-2019 07:00   docProps/app.xml
      595  02-22-2019 07:00   docProps/core.xml
      242  02-22-2019 07:00   docProps/custom.xml
     8125  02-22-2019 07:00   word/document.xml
     2494  02-22-2019 07:00   word/fontTable.xml
     1135  02-22-2019 07:00   word/footnotes.xml
      626  02-22-2019 07:00   word/comments.xml
     2157  02-22-2019 07:00   word/numbering.xml
     2126  02-22-2019 07:00   word/settings.xml
      199  02-22-2019 07:00   word/webSettings.xml
    14247  02-22-2019 07:00   word/styles.xml
     1367  02-22-2019 07:00   word/_rels/document.xml.rels
      301  02-22-2019 07:00   word/_rels/footnotes.xml.rels
     7674  02-22-2019 07:00   word/theme/theme1.xml
---------                     -------
    44566                     16 files
```

実際にzipファイルとして展開してみましょう。

```
$ unzip reference.docx -d reference_docx
Archive:  reference.docx
  inflating: reference_docx/[Content_Types].xml
  inflating: reference_docx/_rels/.rels
  inflating: reference_docx/docProps/app.xml
  inflating: reference_docx/docProps/core.xml
  inflating: reference_docx/docProps/custom.xml
  inflating: reference_docx/word/document.xml
  inflating: reference_docx/word/fontTable.xml
  inflating: reference_docx/word/footnotes.xml
  inflating: reference_docx/word/comments.xml
  inflating: reference_docx/word/numbering.xml
  inflating: reference_docx/word/settings.xml
  inflating: reference_docx/word/webSettings.xml
  inflating: reference_docx/word/styles.xml
  inflating: reference_docx/word/_rels/document.xml.rels
  inflating: reference_docx/word/_rels/footnotes.xml.rels
  inflating: reference_docx/word/theme/theme1.xml
```

ディレクトリ構造を `tree` コマンドで見てみます。

```
$ tree reference_docx
reference_docx
├── [Content_Types].xml
├── _rels
├── docProps
│   ├── app.xml
│   ├── core.xml
│   └── custom.xml
└── word
    ├── _rels
    │   ├── document.xml.rels
    │   └── footnotes.xml.rels
    ├── comments.xml
    ├── document.xml
    ├── fontTable.xml
    ├── footnotes.xml
    ├── numbering.xml
    ├── settings.xml
    ├── styles.xml
    ├── theme
    │   └── theme1.xml
    └── webSettings.xml
```

## 中身の雰囲気のみをつかむ

ここからかなり割愛して、ディレクトリ内の雰囲気をつかんでいきます。

まず注目してほしいのは `word` ディレクトリです。
Wordファイルのコンテンツが、大体ここに入っていると思ってください。

`_rels` ディレクトリなどは、いったん無視して大丈夫です。（ざっくり言えば、OPCに基づき、各ファイル間の関係(relation)を定義しています）


試しに `word/documents.xml` の中身を見てみます。

```
$ cd reference_docx/word
$ cat document.xml
```

```document.xml
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">

  <w:body>
    <w:p>
      <w:pPr>
        <w:pStyle w:val="Title" />
      </w:pPr>
      <w:r>
        <w:t xml:space="preserve">
Title
</w:t>
      </w:r>
    </w:p>
    <w:p>
      <w:pPr>
        <w:pStyle w:val="Subtitle" />
      </w:pPr>
      <w:r>
        <w:t xml:space="preserve">
Subtitle
</w:t>
      </w:r>
    </w:p>

（中略）

    <w:p>
      <w:pPr>
        <w:pStyle w:val="Heading1" />
      </w:pPr>
      <w:bookmarkStart w:id="21" w:name="heading-1" />
      <w:r>
        <w:t xml:space="preserve">
Heading 1
</w:t>
      </w:r>
      <w:bookmarkEnd w:id="21" />
    </w:p>

（中略）

    <w:sectPr />
  </w:body>
</w:document>
```

ひとまず、ここでは**Word文書らしきものが、XMLで定義されている**ということをつかめばOKです。
詳細については、ここでは割愛します。

もっと中身を覗きたい場合は、テキストエディタを使って中身を見てみましょう。
ただし、XMLファイルがminifyされている場合も多いため、XMLの整形ができるエディタ（もしくは拡張機能）を使いましょう。

## まとめ

今の段階では、次のことがわかれば十分です。

- docxファイルはzipアーカイブ（zipとして展開ができる）
- その中身はXMLファイル
- 上記は、主にOffice Open XML (OOXML) という規格で定められている
    - パッケージ構成自体の規格: Open Packaging Convention (OPC)
    - Word docxの詳細な規格: WordprocessingML


## さらに知りたい人へ

- 日本語の資料
    - [Open XML SDK 2.5 for Office へようこそ | Microsoft Docs](https://docs.microsoft.com/ja-jp/office/open-xml/open-xml-sdk)
    - [OOXML（Office Open XML）とは？　概要、メリットと活用アプリケーション - Office Server Document Converter](https://www.antenna.co.jp/sbc/ooxml/i01-0001/i01-0001.html)
    - [Office Open XML（OOXML）仕様とMicrosoft Officeのバージョンの関係 | 電子書籍、電子出版のCAS-UBブログ](http://blog.cas-ub.com/?p=11368)
    - [Officeファイルの成り立ちと最新形、そして標準化 (1/2)：XMLを取り込んだ最新Officeフォーマットとは（前編） - ＠IT](https://www.atmarkit.co.jp/ait/articles/0807/22/news131.html)
- [Office Open XML - Anatomy of an OOXML WordProcessingML File](http://officeopenxml.com/anatomyofOOXML.php)
- Eric White氏の資料（OOXML関係の解説記事やチュートリアル動画をたくさん出している）
    - YouTube: [Eric White - YouTube](https://www.youtube.com/channel/UCbbNZtScS4CR7gQiu3ktY1Q)
    - ブログ: [Eric White | Open XML](http://www.ericwhite.com/blog/)

今回は以上です。

## and more...（勝手に宣伝）

（2020-05-30：技術書典6版から商業版に案内を変更）

**Office Open XMLのディープな入口を案内してくれる本が商業化されました！**
[理音伊織](https://twitter.com/IoriAYANE)さんが技術書典6で頒布された同人誌（通称「茨本」）が底本となっています。

Kindleなど電子書籍、紙の本で読めます。
本気でOpen Office XMLを学びたい人はこの本を読みましょう。

[あと一歩深い情報を得るためのロードマップ～Office Open XMLフォーマットガイド (技術の泉シリーズ（NextPublishing）) ](http://www.amazon.co.jp/dp/B07ZJ4ZZZB/)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E6%8A%80%E8%A1%93%E6%9B%B8%E5%85%B8?src=hash&amp;ref_src=twsrc%5Etfw">#技術書典</a> 6で頒布したOOXML本がインプレスR&amp;Dさんから11/1に発売になります！<br>同人版では書き切れなかった図形関係あたりが増量されています。<br>ぜひに！<br> あと一歩深い情報を得るためのロードマップ～Office Open XMLフォーマットガイド <a href="https://t.co/ZVgLNlFNtS">https://t.co/ZVgLNlFNtS</a></p>&mdash; 理音伊織 (@IoriAYANE) <a href="https://twitter.com/IoriAYANE/status/1189531287108763648?ref_src=twsrc%5Etfw">October 30, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>