GrooveSeek

Semantic search over a Markdown knowledge base, served over MCP.

View the Project on GitHub alphabet-h/grooveseek

27. docx の見出しは style の名前と basedOn の連鎖で決める

背景と課題

この記録までは、.docx parser は段落が名指す style ID の綴りで見出しを決めていた: <w:pStyle w:val="Heading1"> を小文字化し、heading で始まり数字で終わることが条件だった。 style ID は書いたアプリケーションが文書ごとに選ぶ識別子で、名前ではない。日本語 UI の Word は 組み込みの見出しを ID 1 .. 6 で書き、word/styles.xml で heading 1 .. heading 6 と 名付けるので、そう書かれた文書はどの見出しも見出しと認められず、1 chunk で索引されていた。 test の文書は word/styles.xml を持たず Heading1 形の ID を使っていたので、見えなかった。

問いは、段落が見出しだと何が決めるのか、そして使える style を持たない文書をどう読むのか。

判断の軸

検討した選択肢

  1. 何が決めるか。
    • 名前だけ (Apache Tika、unstructured): heading N という名前の style が見出し。却下: 見出し style を基にした独自 style が見出しにならないが、書いた人にとっては見出しである。
    • 名前と w:basedOn の連鎖。派生側の style が outline level を 9 にしていれば見出しを 打ち消す (pandoc の規則 + 打ち消し)。採用。
    • 実効 outline level も使う (docling): 名前によらず outline level 0〜8 の style は見出し。 却下: outline level を持つ本文 style は実在し、docling はその issue (#4106) に答える必要があった。
  2. 表と綴りが食い違う時。
    • どちらかが見出しと言えば見出し。却下: 打ち消しと「名前が見出しでない style」が、ID がたまたま Heading... と綴られている限り覆る — 規則が 2 つになる。
    • 表が持つ ID は表が決め、持たない ID だけ綴りが決める。 採用。
  3. 壊れた styles パート。
    • 壊れる前に読めた style を使う。却下: 親を失った style は連鎖がそこで終わり、表全体とも 綴りとも違う「本文」になり、どの段落がそうなったかが見えない。
    • パートを丸ごと使わず、全段落を綴りで読み、stderr でそう言う。 採用。
  4. 既に読んだパートと合わせると展開 budget に収まらない styles パート。
    • docProps/core.xml と同じく文書ごと失敗させる。却下: 今索引されている文書が、無くても 困らないパートのせいで索引から落ちる。
    • warning 付きでパートを読み飛ばし、綴りに戻る。 採用。

決定

結果と代償

参考