python-docx 進階手術室:從高階 API 到底層 XML (w:p, w:r, w:t) 完全解析; from docx.oxml import OxmlElement ; from docx.oxml.ns import qn

加入好友
加入社群
python-docx 進階手術室:從高階 API 到底層 XML (w:p, w:r, w:t) 完全解析; from docx.oxml import OxmlElement ; from docx.oxml.ns import qn - 儲蓄保險王

在使用 python-docx 時,我們通常使用 add_paragraph() 這種高階指令。但在處理複雜排版(如:插入到特定位置、合併儲存格、處理特殊樣式)時,往往需要「打開引擎蓋」,直接操作底層的 XML 元素。

這篇文章將帶你理解 Word XML 的核心三巨頭:w:p、w:rw:t

第一步:準備測試環境

首先,我們執行這段程式碼,生成一個乾淨的 demo_origin.docx 作為手術對象。

# %%
from docx import Document

def create_demo_doc():
    doc = Document()
    doc.add_heading('原始文件標題', 0)
    doc.add_paragraph('這是原始文件的第一段內容。')
    doc.add_paragraph('這是原始文件的第二段內容。')
    doc.save(r'D:\Temp\demo_origin.docx')
    print("測試檔案 'demo_origin.docx' 已生成!")

if __name__ == "__main__":
    create_demo_doc()

demo_origin.docx:

python-docx 進階手術室:從高階 API 到底層 XML (w:p, w:r, w:t) 完全解析; from docx.oxml import OxmlElement ; from docx.oxml.ns import qn - 儲蓄保險王

第二步:實戰演練 —— 三種寫法比較

現在,我們要達成一個目標:在文件的「最開頭」插入一段文字:「這是插入的標題」。

請看以下三種方法的實作與比較:

# %%
from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

# 讀取剛剛生成的檔案
doc = Document(r'D:\Temp\demo_origin.docx')
body = doc.element.body  # 取得 XML  Body 元素

# =====================================================
# 方法一高階 API (High-Level) - 最簡單但只能插在最後
# =====================================================
print("--- 執行方法一 ---")
# 限制add_paragraph 預設只能 Append 到文件最後面
p = doc.add_paragraph('方法一:我是高階 API 產生的段落 (在最後面)')


# =====================================================
# 方法二底層 XML (Low-Level) - 最靈活可插在任意位置
# =====================================================
print("--- 執行方法二 ---")
# 這是你在 split_diagnostics.py 看到的寫法
# 我們要手動組裝 XML 結構: <w:p> -> <w:r> -> <w:t>

# 1. 建立段落 (Paragraph)
p_elem = OxmlElement('w:p')

# 2. 建立樣式片段 (Run)
r_elem = OxmlElement('w:r')

# 3. 建立文字節點 (Text)
t_elem = OxmlElement('w:t')
t_elem.text = '方法二:我是底層 XML 組裝的段落 (插在最前面)'

# 4. 層層組裝 (Append)
r_elem.append(t_elem)  # 把文字裝進 Run
p_elem.append(r_elem)  #  Run 裝進 Paragraph

# 5. 插入到 Body 的指定位置 (Index 0 = 最前面)
body.insert(0, p_elem)


# =====================================================
# 方法三混合技 (Hybrid) - 先建後移 (推薦!)
# =====================================================
print("--- 執行方法三 ---")
# 結合高階的便利與底層的靈活

# 1. 用高階 API 快速建立 (此時它在最後面)
new_p = doc.add_paragraph('方法三:我是混合技產生的段落 (原本在後,被移到前)')
new_p.runs[0].bold = True # 還可以順便設定樣式超方便

# 2. 取得底層 XML 元素
p_element = new_p._element

# 3. 乾坤大挪移先移除再插入到指定位置
body.remove(p_element) # 從尾巴拔出來
body.insert(1, p_element) # 插在 index 1 (剛好在方法二的後面)


# 存檔看結果
doc.save(r'D:\Temp\demo_result.docx')
print("操作完成!請開啟 'demo_result.docx' 查看結果。")

程式輸出:

python-docx 進階手術室:從高階 API 到底層 XML (w:p, w:r, w:t) 完全解析; from docx.oxml import OxmlElement ; from docx.oxml.ns import qn - 儲蓄保險王

demo_result.docx

python-docx 進階手術室:從高階 API 到底層 XML (w:p, w:r, w:t) 完全解析; from docx.oxml import OxmlElement ; from docx.oxml.ns import qn - 儲蓄保險王

第三步:結構解析 (為什麼要這麼麻煩?)

在 方法二 中,我們手動建立了三個物件,這對應了 Word XML 的階層結構:

  1. w:p (Paragraph) – 段落
    對應變數:p_elem = OxmlElement(‘w:p’)
    意義:這是文件的一個「塊狀」容器。它包含了對齊方式、縮排、行距等資訊,但不包含文字內容。
    高階物件:doc.add_paragraph() 回傳的 Paragraph 物件。
  2. w:r (Run) – 樣式片段 (連續文字串)
    對應變數:r_elem = OxmlElement(‘w:r’)
    意義:這是 Word 中最難理解的概念。它是「具有相同格式的一連串文字」
    為什麼需要它?
    如果你的一句話裡,前半段是粗體,後半段是斜體,Word 必須把它拆成兩個 Run。
    Run 1 (Bold): “前半段”
    Run 2 (Italic): “後半段”
    高階物件:paragraph.add_run() 回傳的 Run 物件。
  3. w:t (Text) – 文字內容
    對應變數:t_elem = OxmlElement(‘w:t’)
    意義:這才是真正存放文字字串的地方。
    注意:它必須被包在 w:r 裡面,不能直接放在 w:p 裡。
    結構圖解
<w:body>  (文件主體)
  |
  +-- <w:p> (段落 1)
  |     |
  |     +-- <w:r> (樣式片段 1: 正常文字)
  |     |     |
  |     |     +-- <w:t> "Hello" </w:t>
  |     |
  |     +-- <w:r> (樣式片段 2: 粗體文字)
  |           |
  |           +-- <w:rPr><w:b/></w:rPr> (屬性: 粗體)
  |           +-- <w:t> "World" </w:t>
  |
  +-- <w:tbl> (表格)...

總結
高階 API (add_paragraph)
幫你自動包裝好了 p -> r -> t 的過程,適合一般寫入(預設加在最後面)。

底層 XML (OxmlElement)
當你需要「插入到特定位置」(例如 body.insert(0, …))或修改特殊屬性時使用。

混合技 (Hybrid)
利用高階 API 建立內容,再利用底層 API 移動位置。這是 CP 值最高

的寫法,既有高階的便利,又有底層的靈活。

推薦hahow線上學習python: https://igrape.net/30afN

加入好友
加入社群
python-docx 進階手術室:從高階 API 到底層 XML (w:p, w:r, w:t) 完全解析; from docx.oxml import OxmlElement ; from docx.oxml.ns import qn - 儲蓄保險王

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡

You may also like...

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *