DOCXの非公式な紹介
公開: 2022-03-11約10億人がMicrosoftOfficeを使用しているため、DOCX形式は、オフィス間でドキュメントファイルを交換するための最も一般的なデファクトスタンダードです。 最も近い競合製品であるODT形式は、Open / LibreOfficeと一部のオープンソース製品でのみサポートされており、標準からはほど遠いものになっています。 PDFは編集できず、完全なドキュメント構造が含まれていないため、PDF形式は競合他社ではありません。そのため、透かしや署名などの限られたローカル変更のみを行うことができます。 これが、ほとんどのビジネスドキュメントがDOCX形式で作成される理由です。 それを置き換える良い代替手段はありません。
DOCXは複雑な形式ですが、インデックス作成、TXTへの変換、その他の小さな変更などの単純なタスクのために、手動で解析することをお勧めします。 DOCXの内部に関する十分な情報を提供したいので、5,000ページの膨大なマニュアルであるECMA仕様を参照する必要はありません。
形式を理解する最良の方法は、MSWordを使用して単純な1ワードのドキュメントを作成し、ドキュメントを編集すると基になるXMLがどのように変化するかを観察することです。 DOCXがMSWordで正しくフォーマットされておらず、その理由がわからない場合や、目的のフォーマットを生成する方法が明確でない場合に遭遇する場合があります。 XMLで何が起こっているのかを正確に見て理解することは、それを助けるでしょう。
私は約1年間、共同DOCXエディターであるCollabOfficeに携わっていましたが、その知識の一部を開発者コミュニティと共有したいと思います。 この記事では、DOCXファイルの構造について説明し、インターネット上に散在する情報を要約します。 この記事は、巨大で複雑なECMA仕様と、現在利用可能な単純なインターネットチュートリアルの中間です。 この記事に付随するファイルは、私のgithubアカウントのtoptal-docx
プロジェクトにあります。
シンプルなDOCXファイル
DOCXファイルは、XMLファイルのZIPアーカイブです。 新しい空のMicrosoftWord文書を作成し、その中に「Test」という単語を1つ書き込んで内容を解凍すると、次のファイル構造が表示されます。
単純なドキュメントを作成しましたが、Microsoft Wordの保存プロセスでは、デフォルトのテーマ、ドキュメントプロパティ、フォントテーブルなどがXML形式で生成されています。
まず、未使用のものを削除し、メインのテキスト要素を含むdocument.xml
に注目しましょう。 ファイルを削除するときは、そのファイルへのすべての関係参照を他のxmlファイルから削除したことを確認してください。 これは、app.xmlとcore.xmlへの依存関係をクリアした方法のコード差分の例です。 未解決/欠落している参照がある場合、MSWordはファイルが壊れていると見なします。
簡略化された最小限のDOCXドキュメントの構造は次のとおりです(これがgithubのプロジェクトです)。
ここから、上からファイルごとに分類してみましょう。
_rels / .rels
これは、MSWordにドキュメントの内容を探す場所を指示する参照を定義します。 この場合、 word/document.xml
を参照します。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> <Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/> </Relationships>
_rels / document.xml.rels
このファイルは、ドキュメントコンテンツに埋め込まれた画像などのリソースへの参照を定義します。 単純なドキュメントにはリソースが埋め込まれていないため、リレーションシップタグは空です。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> </Relationships>
[Content_Types] .xml
[Content_Types].xml
には、ドキュメント内のメディアの種類に関する情報が含まれています。 テキストコンテンツしかないので、とても簡単です。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <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="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/> </Types>
document.xml
最後に、これがドキュメントのテキストコンテンツを含むメインXMLです。 わかりやすくするために名前空間宣言の一部を削除しましたが、ファイルの完全版はgithubプロジェクトにあります。 そのファイルには、ドキュメント内の名前空間参照の一部が使用されていないことがわかりますが、MS Wordがそれらを必要とするため、それらを削除しないでください。
簡略化した例を次に示します。
<w:document> <w:body> <w:pw:rsidR="005F670F" w:rsidRDefault="005F79F5"> <w:r><w:t>Test</w:t></w:r> </w:p> <w:sectPr w:rsidR="005F670F"> <w:pgSz w:w="12240" w:h="15840"/> <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/> <w:cols w:space="720"/> <w:docGrid w:linePitch="360"/> </w:sectPr> </w:body> </w:document>
メインノード<w:document>
はドキュメント自体を表し、 <w:body>
には段落が含まれ、<w:body <w:body>
内にネストされているのは<w:sectPr>
で定義されたページのサイズです。
<w:rsidR>
は、無視できる属性です。 MSWordの内部で使用されます。
3つの段落からなるより複雑なドキュメントを見てみましょう。 Microsoft Wordのスクリーンショットで同じ色でXMLを強調表示したので、相関関係を確認できます。
<w:pw:rsidR = "0081206C" w:rsidRDefault = "00E10CAE"> <w:r> <w:t xml:space="preserve">これは最初の段落の例です。 デフォルトは左揃えですが、ここで紹介します</ w:t> </ w:r> <w:r> <w:rPr> <w:rFonts w:ascii = "Arial" w:hAnsi = "Arial" w:cs = "Arial" /> <w:color w:val = "000000" /> </ w:rPr> <w:t>太字</ w:t> </ w:r> <w:r> <w:rPr> <w:rFonts w:ascii = "Arial" w:hAnsi = "Arial" w:cs = "Arial" /> <w:b /> <w:color w:val = "000000" /> </ w:rPr> <w:t xml:space ="preserve">テキスト</w:t> </ w:r> <w:r> <w:rPr> <w:rFonts w:ascii = "Arial" w:hAnsi = "Arial" w:cs = "Arial" /> <w:color w:val = "000000" /> </ w:rPr> <w:t xml:space = "preserve">、</ w:t> </ w:r> <w:proofErr w:type = "gramStart" /> <w:r> <w:t xml:space ="preserve">また</w:t> </ w:r>を変更します <w:rw:rsidRPr = "00E10CAE"> <w:rPr> <w:rFonts w:ascii = "Impact" w:hAnsi = "Impact" /> </ w:rPr> <w:t>フォントスタイル</ w:t> </ w:r> <w:r> <w:rPr> <w:rFonts w:ascii = "Impact" w:hAnsi = "Impact" /> </ w:rPr> <w:t xml:space = "preserve"> </ w:t> </ w:r> <w:r> <w:t>から「影響」へ。</ w:t> </ w:r> </ w:p> <w:pw:rsidR = "00E10CAE" w:rsidRDefault = "00E10CAE"> <w:r> <w:t>これは新しい段落です。</ w:t> </ w:r> </ w:p >> <w:pw:rsidR = "00E10CAE" w:rsidRPr = "00E10CAE" w:rsidRDefault = "00E10CAE"> <w:r> <w:t>これはもう1段落で、もう少し長くなります。</ w:t> </ w:r> </ w:p>
段落構造
単純なドキュメントは段落で構成され、段落は実行(同じフォント、色などの一連のテキスト)で構成され、実行は文字( <w:t>
など)で構成されます。 <w:t>
タグには複数の文字が含まれている場合があり、同じ実行でいくつかの文字が含まれている場合があります。
ここでも、 <w:rsidR>
は無視できます。
テキストのプロパティ
基本的なテキストプロパティは、フォント、サイズ、色、スタイルなどです。 テキストの外観を指定するタグは約40個あります。 3つの段落の例でわかるように、各実行には<w:rPr>
内に独自のプロパティがあり、 <w:color>
、 <w:rFonts>
、および太字<w:b>
を指定します。
注意すべき重要な点は、プロパティは通常のスクリプトと複雑なスクリプト(アラビア語など)の2つの文字グループを区別し、影響を受ける文字のタイプに応じてプロパティのタグが異なることです。
ほとんどの通常のスクリプトプロパティタグには、プロパティが複雑なスクリプト用であることを指定する「C」が追加された、一致する複雑なスクリプトタグがあります。 例: <w:i>
(斜体)は<w:iCs>
になり、通常のスクリプトの太字タグ<w:b>
は、複雑なスクリプトの<w:bCs>
になります。
スタイル
Microsoft Wordには、スタイル専用のツールバー全体があります。通常、間隔なし、見出し1、見出し2、タイトルなどです。 これらのスタイルは/word/styles.xml
に保存されます(注:簡単な例の最初のステップでは、このXMLをDOCXから削除しました。これを確認するには、新しいDOCXを作成してください)。
テキストをスタイルとして定義すると、段落のプロパティタグ<w:pPr>
内にこのスタイルへの参照が表示されます。 これは、見出し1のスタイルでテキストを定義した例です。
<w:p> <w:pPr> <w:pStyle w:val="Heading1"/> </w:pPr> <w:r> <w:t>My heading 1</w:t> </w:r> </w:p>
これがstyles.xml
のスタイル自体です:
<w:style w:type="paragraph" w:style> <w:name w:val="heading 1"/> <w:basedOn w:val="Normal"/> <w:next w:val="Normal"/> <w:link w:val="Heading1Char"/> <w:uiPriority w:val="9"/> <w:qFormat/> <w:rsid w:val="002F7F18"/> <w:pPr> <w:keepNext/> <w:keepLines/> <w:spacing w:before="480" w:after="0"/> <w:outlineLvl w:val="0"/> </w:pPr> <w:rPr> <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi"/> <w:b/> <w:bCs/> <w:color w:val="365F91" w:themeColor="accent1" w:themeShade="BF"/> <w:sz w:val="28"/> <w:szCs w:val="28"/> </w:rPr> </w:style>
<w:style/w:rPr/w:b>
xpathはフォントが太字であることを指定し、 <w:style/w:rPr/w:color>
はフォントの色を示します。 <w:basedOn>
は、不足しているプロパティに「通常」スタイルを使用するようにMSWordに指示します。

プロパティの継承
テキストプロパティは継承されます。 実行には独自のプロパティ( w:p/w:r/w:rPr/*
)がありますが、段落( w:r/w:pPr/*
)からプロパティを継承し、どちらも/word/styles.xml
からスタイルプロパティを参照できます。 /word/styles.xml
。
<w:r> <w:rPr> <w:rStyle w:val="DefaultParagraphFont"/> <w:sz w:val="16"/> </w:rPr> <w:tab/> </w:r>
段落と実行は、デフォルトのプロパティw:styles/w:docDefaults/w:rPrDefault/*
およびw:styles/w:docDefaults/w:pPrDefault/*
で始まります。 キャラクターのプロパティの最終結果を取得するには、次のことを行う必要があります。
- デフォルトの実行/段落プロパティを使用する
- 実行/段落スタイルのプロパティを追加する
- ローカルの実行/段落プロパティを追加します
- 段落プロパティの上に結果実行プロパティを追加します
BをAに「追加」と言うときは、すべてのBプロパティを反復処理し、すべてのAのプロパティをオーバーライドして、交差しないすべてのプロパティをそのままにすることを意味します。
デフォルトのプロパティを配置できるもう1つの場所は、 w:type="paragraph"
およびw:default="1"
の<w:style>
タグです。 実行内の文字自体にデフォルトのスタイルが設定されることはないため、 <w:style w:type="character" w:default="1">
は実際にはテキストに影響を与えないことに注意してください。
1554402290400-dbb29eef3ba6035df7ad726dfc99b2af.png)
プロパティを切り替えます
一部のプロパティは、 <w:b>
(太字)や<w:i>
(斜体)などの「トグル」プロパティです。 これらの属性はXOR演算子のように動作します。
これは、親スタイルが太字で子ランが太字の場合、結果は通常の太字ではないテキストになることを意味します。
トグル属性を正しく処理するには、多くのテストとリバースエンジニアリングを行う必要があります。 ECMA-376 Open XML仕様の17.7.3項を参照して、トグルプロパティの正式で詳細なルールを取得してください。
フォント
フォントは他のテキスト属性と同じ一般的な規則に従いますが、フォントプロパティのデフォルト値は、次のようにword/_rels/document.xml.rels
で参照される別のテーマファイルで指定されます。
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
上記の参照に基づいて、デフォルトのフォント名は、 word/theme/themes1.xml
の<a:theme>
タグ、 a:themeElements/a:fontScheme/a:majorFont
、またはa:minorFont
タグ内にあります。
w:docDefaults/w:rPrDefault
タグがない場合を除き、デフォルトのフォントサイズは10で、サイズは11です。
テキストの配置
テキストの配置は、 "left"
、 "center"
、 "right"
、 "both"
の4つのw:val
モードを使用できる<w:jc>
タグで指定されます。
"left"
がデフォルトのモードです。 テキストは、段落の長方形の左側(通常はページ幅)から始まります。 (この段落は、標準の左側に配置されています。)
"center"
モードは、予想通り、すべての文字をページ幅内に中央揃えします。 (繰り返しますが、この段落は中央揃えを例示しています。)
"right"
モードでは、段落テキストは右マージンに揃えられます。 (このテキストが右側にどのように配置されているかに注意してください。)
"both"
モードでは、単語間に余分な間隔を空けて、行が広くなり、段落の幅全体を占めるようにします。ただし、最後の行は左揃えになります。 (この段落はそのデモンストレーションです。)
画像
DOCXは、インラインとフローティングの2種類の画像をサポートしています。
インライン画像は他の文字と一緒に段落内に表示されます。 <w:t>
(テキスト)を使用する代わりに<w:drawing>
が使用されます。 次のxpath構文でイメージIDを見つけることができます。
w:drawing/wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip/@r:embed
画像IDは、 word/_rels/document.xml.rels
ファイルでファイル名を検索するために使用され、word/mediaサブフォルダー内のgif/jpegファイルを指している必要があります。 (githubプロジェクトのword/_rels/document.xml.rels
ファイルを参照してください。ここでイメージIDを確認できます。)
フローティング画像は、テキストが周囲に流れる段落を基準にして配置されます。 (これは、フローティングイメージを使用したgithubプロジェクトのサンプルドキュメントです。)
フローティング画像は<w:drawing>
の代わりに<wp:anchor>
を使用するため、 <w:p>
内のテキストを削除する場合、画像を削除したくない場合はアンカーに注意してください。
テーブル
テーブルのXMLタグは、HTMLテーブルのマークアップに似ています– <tr>などと一致します。
テーブル自体である<w:tbl>
にはテーブルプロパティ<w:tblPr>
があり、各列プロパティは<w:gridCol>
内の<w:tblGrid>
>によって表されます。 行は<w:tr>
タグとして1つずつ続き、各行には<w:tblGrid>
で指定されたのと同じ数の列が必要です。
<w:tbl> <w:tblPr> <w:tblW w:w="5000" w:type="pct" /> </w:tblPr> <w:tblGrid><w:gridCol/><w:gridCol/></w:tblGrid> <w:tr> <w:tc><w:p><w:r><w:t>left</w:t></w:r></w:p></w:tc> <w:tc><w:p><w:r><w:t>right</w:t></w:r></w:p></w:tc> </w:tr> </w:tbl>
テーブル列の幅は<w:tblW>
タグで指定できますが、定義しない場合、MS Wordは内部アルゴリズムを使用して、最小の有効なテーブルサイズに最適な列幅を見つけます。
単位
DOCX内の多くのXML属性は、サイズまたは距離を指定します。 これらはXML内の整数ですが、すべて異なる単位を持っているため、変換が必要です。 トピックは複雑なので、DOCXファイルのユニットに関するLarsCorneliussenによるこの記事をお勧めします。 彼が提示する表は便利ですが、わずかなミスプリントがあります。インチはpt*72ではなくpt/72である必要があります。
チートシートは次のとおりです。
一般的なDOCXXML単位の変換 | ||||||
ポイントの20番目 | ポイント dxa / 20 | インチ pt / 72 | センチメートル in * 2,54 | フォントのハーフサイズ pt / 144 | EMU in * 914400 | |
例 | 11906 | 595.3 | 8,27… | 21.00086… | 4,135 | 7562088 |
これを使用したタグ | pgSz / pgMar / w:spacing | w:sz | wp:extent、a:ext |
レイアウトツールを実装するためのヒント
DOCXファイルを(たとえばPDFに)変換したり、キャンバスに描画したり、ページ数をカウントしたりする場合は、レイアウトツールを実装する必要があります。 レイアウトツールは、DOCXファイルから文字の位置を計算するためのアルゴリズムです。
100%忠実なレンダリングが必要な場合、これは複雑な作業です。 優れたレイアウトツールを実装するために必要な時間は人年で測定されますが、単純で限られたものだけが必要な場合は、比較的迅速に実行できます。
レイアウト担当者は、通常はページの長方形である親の長方形を塗りつぶします。 実行から単語を1つずつ追加します。 現在の行がオーバーフローすると、新しい行が開始されます。 段落が親の長方形に対して高すぎる場合は、次のページに折り返されます。
レイアウトツールを実装する場合は、次の点に注意してください。
- レイアウト担当者は、テキストの配置と画像上に浮かぶテキストに注意する必要があります
- ネストされたテーブルなどのネストされたオブジェクトを処理できる必要があります
- このような画像を完全にサポートする場合は、少なくとも2つのパスでレイアウトツールを実装する必要があります。最初のステップではフローティング画像の位置を収集し、2番目のステップでは空のスペースをテキスト文字で埋めます。
- インデントと間隔に注意してください。 各段落には前後に間隔があり、これらの番号は
w:spacing
タグで指定されます。 垂直方向の間隔は、w:after
タグとw:before
タグで指定されます。 行間隔はw:line
で指定されますが、これは予想される行のサイズではないことに注意してください。 行のサイズを取得するには、現在のフォントの高さを取得し、w:line
を掛けて、12で割ります。 - DOCXファイルには、ページ付けに関する情報は含まれていません。 ページ数を確認するために各行に必要なスペースを計算しない限り、ドキュメントのページ数はわかりません。 ページ上の各文字の正確な座標を見つける必要がある場合は、すべての間隔、インデント、およびサイズを考慮に入れてください。
- テーブルを処理するフル機能のDOCXレイアウトツールを実装する場合は、テーブルが複数のページにまたがる特殊なケースに注意してください。 ページオーバーフローを引き起こすセルは、他のセルにも影響します。
- テーブルの列の幅を計算するための最適なアルゴリズムを作成することは、難しい数学の問題であり、ワードプロセッサとレイアラーは通常、いくつかの次善の実装を使用します。 最初の近似として、W3CHTMLテーブルのドキュメントのアルゴリズムを使用することを提案します。 MS Wordで使用されるアルゴリズムの説明は見つかりませんでした。また、Microsoftはアルゴリズムを時間の経過とともに微調整してきたため、Wordのバージョンが異なればテーブルのレイアウトもわずかに異なる可能性があります。
不明な点がある場合:XMLをリバースエンジニアリングしてください!
これまたはそのXMLタグがMSWord内でどのように機能するかが明らかでない場合、それを理解するための2つの主要なアプローチがあります。
目的のコンテンツを段階的に作成します。 単純なdocxファイルから始めます。 たとえば、
1.docx
、2.docx
のように、各ステップを独自のファイルに保存します。 それぞれを解凍し、視覚的な差分ツールを使用してフォルダーを比較し、変更後にどのタグが表示されるかを確認します。 (商用オプションの場合はAraxis Mergeを、無料オプションの場合はWinMergeを試してください。)MS Wordが気に入らないDOCXファイルを生成する場合は、逆方向に作業してください。 XMLを段階的に簡素化します。 ある時点で、MSWordが正しくないことがわかった変更を学習します。
DOCXは非常に複雑ですよね?
これは複雑であり、Microsoftのライセンスでは、サーバー側でDOCXを処理するためにMSWordを使用することを禁じています。これは商用製品のかなり標準的な方法です。 ただし、MicrosoftはほとんどのDOCXタグを処理するためのXSLTファイルを提供していますが、100%または99%の忠実度を提供することはできません。 画像のテキストの折り返しなどのプロセスはサポートされていませんが、ほとんどのドキュメントをサポートできます。 (複雑さが必要ない場合は、代わりにMarkdownを使用することを検討してください。)
十分な予算がある場合(無料のDOCXレンダリングエンジンがない場合)、Asposeやdocx4jなどの商用製品を使用することをお勧めします。 最も人気のある無料のソリューションは、DOCXとPDFを含む他の形式の間で変換するためのLibreOfficeです。 残念ながら、LibreOfficeには変換中に多くの小さなバグが含まれています。また、LibreOfficeは洗練されたオープンソースのC ++製品であるため、忠実度の問題を修正するのに時間がかかり、困難です。
または、DOCXレイアウトが複雑すぎて自分で実装できない場合は、それをHTMLに変換し、ブラウザーを使用してレンダリングすることもできます。 ToptalのフリーランスXML開発者の1人を検討することもできます。
さらに読むためのDOCXリソース
- ECMADOCX仕様
- C#からのDOCX操作用のOpenXMLライブラリ。 コードのレイアウトやレンダリングに関する情報は含まれていませんが、DOCXで可能な各XMLノードに一致するクラス階層を提供します。
- docx4j、OpenXML、docxなどのキーワードを使用して、stackoverflowでいつでも検索または質問できます。 コミュニティには知識のある人がいます。