DOCX の再現性とセキュリティ
Next.js のエクスポート用エンドポイントは、ネイティブの WordprocessingML パッケージをローカルで生成します。この表は、リポジトリで実際に動いているパッケージ単位の再現性テストに基づいています。ブラウザーの任意の CSS に、Word で 1 対 1 に対応するものがあると主張するものではありません。2 つの要素については個別に解説しています。Word を往復しても崩れない数式と、.docx の中身は実際にどうなっているかです。
テスト済みの対応
| 分野 | ネイティブの DOCX 出力 |
|---|---|
| 文書の構造 | 見出し、段落、引用ブロック、入れ子の箇条書きと数字のリスト、固定レイアウトの表 |
| インラインの書式 | 太字、斜体、下線、取り消し線、コード、フォントの種類とサイズ、文字色/背景色、下付き文字と上付き文字 |
| 段落のレイアウト | 配置、余白、行の高さ、1 行目のインデント、page-break-before と明示的な改ページ |
| ページのレイアウト | Letter または A4、縦向きまたは横向き、範囲が制限された余白、既定のヘッダーとフッター、現在のページ/総ページ数のフィールド |
| 表 | 正確な DXA のグリッド、繰り返される見出し行、列の結合、行の結合、セルの網掛けと垂直方向の配置 |
| レビューの意味 | ネイティブの DOCX の挿入、削除、コメント、脚注、文末脚注 |
| 数式 | LaTeX をネイティブの OMML に変換。分数、上付き・下付き、根号、n 項演算子、区切り記号、関数、極限、アクセント、バー、ボックス。画像ではなく、Word の数式エディターで編集可能 |
| リンクとメディア | HTTP/HTTPS/mailto のリンク。PNG、JPEG、GIF、BMP の data URI。サーバーが解決する信頼できる画像マップ |
リクエストの仕様
POST /api/export/docx
{
"html": "<h1>Report</h1><p>Body</p>",
"title": "Report",
"fileName": "report.docx",
"headerHtml": "<p>Private report</p>",
"footerHtml": "<p>Page <span data-page-number="current"></span></p>",
"page": { "size": "a4", "orientation": "landscape",
"margin": { "top": 1080, "right": 900, "bottom": 1080, "left": 900 } },
"imageMap": { "https://trusted.example/chart.png": "data:image/png;base64,..." }
}余白は 20 分の 1 ポイント(twip)単位で、360 から 2880 の範囲に制限されます。リクエストの上限は 1 MiB です。画像マップが受け付けるのは、最大 8 個の HTTP(S) のキーと、data 形式の画像の値だけで、デコード後の合計は 768 KiB までです。
セマンティック HTML の規約
<ins data-author="Ada" data-date="2026-07-16T12:00:00Z">added</ins>
<del data-author="Ada">removed</del>
<span data-comment="Check the source" data-comment-author="Reviewer">claim</span>
<sup data-footnote="Source citation"></sup>
<span data-endnote="Appendix detail"></span>
<hr class="page-break">DOCX のインポート
インポートは、ライブラリもサーバーとの往復もなしに、すべてブラウザー内で行われます。.docx は XML の ZIP なので、ZIP のセントラルディレクトリを直接読み取り、展開は DecompressionStream("deflate-raw") が行います。どこにも何もアップロードされません。
| インポートされるもの | 方法と、単純な変換ツールで失われるもの |
|---|---|
| ハイパーリンクの URL | w:hyperlink が持つのは r:id だけで、アドレスは word/_rels/document.xml.rels にあります。これを解決します。解決しないと、すべてのリンクが URL を捨てたプレーンテキストとしてインポートされます。 |
| 画像 | w:drawing → a:blip → word/media/* をたどり、data URI としてインラインにします。画像の多いファイルでスキップするには documentImportImages: false を設定します。 |
| 番号付きリストと箇条書き | document.xml はすべてのリストを同じように保存しており、それらを区別するのは word/numbering.xml だけです。これを読み取るので、番号付きリストは箇条書きにならず <ol> のままです。 |
| リストの入れ子 | w:ilvl から本物の入れ子を作り、サブリストを親の <li> の中に置くので、マークアップは有効です。 |
| 脚注と文末脚注 | Word は注の本文を別々のパート(word/footnotes.xml と word/endnotes.xml)に保存し、document.xml が持つのは id だけです。すべて読み取り、動的な注として再構築します。インポートした注の前に注を挿入すると、すべての番号が振り直されます。2 つのパートはスキーマを共有していますが、要素名(w:footnote と w:endnote)は異なるので、一方のために書いたパーサーは、もう一方については黙って何も返しません。Word の区切り線のエントリはスキップします。 |
| テキストボックス | テキストボックスの内容はラン(run)の 6 階層下(w:pict → v:shape → v:textbox → w:txbxContent)に入れ子になっているので、直下の子要素だけを読む変換ツールでは、その中の言葉がすべて失われます。段落や表をそのまま保って、文書の順序どおりに .rte-imported-textbox ブロックとして復元します。mc:AlternateContent ブロックには同じボックスが 2 回(DrawingML 版と VML のフォールバック)含まれていますが、出力するのは 1 つだけです。 |
| 変更履歴とコメント | w:ins と w:del は、作成者と日付付きの <ins>/<del> としてインポートされます。エクスポートが出力するのと同じ規約なので、レビューのマークアップは往復で保たれます。削除されたテキストは w:t ではなく w:delText にあります。コメントの範囲は、word/comments.xml から本文を取り出した data-comment の span になります。 |
| 数式 | Word は数式を、独自の数式名前空間の m:oMath ツリーとして、ランの間に挟み込んで保存します。w:r 要素をたどる変換ツールはこれを見ることがなく、周りの文は問題なくインポートされるのに、数式だけが消えてしまいます。数式は LaTeX に変換され、エディター独自の rte-math-inline の span として出力されるので、数式のダイアログで編集でき、ページが読み込むレンダラーで描画されます。分数、下付き・上付き、根号、n 項演算子(演算子はテキストではなく属性です)、区切り記号、関数、極限、アクセント、バー、行列、整列された配列を変換し、認識できないものは消さずに元のテキストのまま残します。 |
| SmartArt | document.xml 内の図が持つのはリレーションシップの id だけで、図の言葉はすべて別の名前空間の word/diagrams/dataN.xml にあります。そのため、a:blip を探す読み取り処理は何も見つけられず、図全体を落としてしまいます。レイアウトは HTML では再現できませんが、内容は .rte-imported-smartart のアウトラインとして復元します。リストとしてインポートされた組織図は使えますが、空白としてインポートされたものは欠落になってしまいます。Word のプレゼンテーション用と接続用のポイント(pres、parTrans、sibTrans)には内容がないので、スキップします。 |
| WMF/EMF の画像 | Windows のメタファイルにはブラウザーで描画できる形式がないので、インラインにできません。跡形もなく消えるのではなく、それぞれ data-source を持つ名前付きのプレースホルダーを残すので、読者はそこに図があったことと、元の文書でどれを探せばよいかがわかります。 |
| 文字の書式 | 色(w:color)、蛍光ペン、上付き/下付き、サイズ。w:sz は半ポイント単位なので、36 は 36pt ではなく 18pt になります。 |
| 構造と書式 | w:pStyle による見出し、表、段落の配置、太字、斜体、下線、取り消し線、タブ、改行。 |
Markdown、HTML、プレーンテキスト、Word の HTML 風の .doc も同じ方法で扱います。それ以外のもの、あるいは独自のサービスを通して変換したい場合は、config.documentImportResolver(file) を指定してください。これはすべての形式で優先されます。
既知の制限。ただし、それは内容ではなく形の制限です。現在、.docx の中のものが黙って捨てられることはありません。HTML で再現できないものは、目に見える形で品質を落とし、そのことを示します。テキストボックスはフローティングの枠ではなく内容として戻り(ブラウザーの HTML には、Word のページへの絶対位置の固定に相当するものがありません)、SmartArt はレイアウトされた図ではなくアウトラインとして、WMF/EMF の画像は名前付きのプレースホルダーとして戻ります。数式は LaTeX として届くので、ソースではなく数式として描画するには、ページに KaTeX または MathJax が必要です。これらはインポートの不足点で、エクスポートの不足点ではありません。現在往復で保たれるものは上の表のとおりです。数式は、2 つの独立した機能としてではなく、本当の往復として検証しています。OOXML にエクスポートして再度インポートした 15 個の数式は、異なる生成ツールが出力する、見た目が同じ 3 種類の Unicode の山かっこも含めて、バイト単位で同一のまま戻ります。
セキュリティの境界
変換ツールがネットワークからの取得を行うことはありません。img 要素の URL は、呼び出し側のサーバーが imageMap に URL から data URI への正確なエントリを指定しない限り、無視されます。これにより、DNS、リダイレクト、プライベートアドレス、認証情報、テナントの認可は、変換ツールの信頼境界の外に置かれます。
意図的な制限
- Word はページ単位で、ブラウザーの HTML はフローレイアウトです。フロート、CSS グリッド、フィルター、スクリプト、フォーム、アニメーション、任意のスタイルは変換しません。
- 使えるのは既定のセクションのヘッダーとフッターだけです。先頭ページ/偶数ページ用のものや、HTML で定義した複数のセクションには、アプリケーション固有のテンプレートが必要です。
- 自動テストは、生成された OOXML のパートとリレーションシップを検査します。ブランドのテンプレートについては、Microsoft Word や LibreOffice での目視による確認が、引き続きリリースの手順の 1 つです。