Python-docx 進階心法:穿梭於「表層 Paragraph」與「底層 CT_P」之間

加入好友
加入社群
Python-docx 進階心法:穿梭於「表層 Paragraph」與「底層 CT_P」之間 - 儲蓄保險王

在使用 python-docx 自動化處理 Word 文件時,我們通常操作的是 Paragraph 物件。但當你需要更精細的控制(例如遍歷 document.element.body)時,你會遇到它的真面目——CT_P

這兩者看似相似,但在屬性存取上有著關鍵的設計哲學差異。

1. 角色介紹

  • Paragraph (高層物件)
    • 身分:它是 python-docx 封裝好的「代理人」。
    • 特點:介面友善,屬性通常會自動處理型別轉換(例如把樣式轉為物件,而不只是字串 ID)。
    • 取得方式doc.paragraphs[0]
  • CT_P (底層元素)
    • 身分:它是 XML 結構在 Python 中的直接映射 (Complex Type Paragraph)。
    • 特點:它是資料的「本體」。雖然它是 XML 元素,但 python-docx 貼心地為它加上了一些 Python 屬性(如 .text),讓它比純 XML 更強大。
    • 取得方式paragraph._element 或直接遍歷 doc.element.body

2. 實戰比對:讀取文字 (.text)

這是最容易讓人誤會的地方。兩者都能讀取文字,但背後的機制不同。

程式碼範例

from docx import Document

doc = Document(r"D:\Temp\demo.docx")
p_obj = doc.paragraphs[0]  # 取得高層物件
ct_p = p_obj._element      # 取得底層物件 (CT_P)

# --- 1. 讀取文字 ---
print(f"Paragraph 文字: {p_obj.text}") 
print(f"CT_P 文字:      {ct_p.text}")
Python-docx 進階心法:穿梭於「表層 Paragraph」與「底層 CT_P」之間 - 儲蓄保險王

差異解析

  • Paragraph.text
    標準用法。它會遍歷段落內所有的 Run,將文字接起來回傳。
  • CT_P.text
    這是一個特異功能。 在標準 lxml (XML 解析庫) 中,父節點通常讀不到子節點的文字。但 python-docx 的作者在 CT_P 類別中手動覆寫.text 屬性,讓它去掃描底下所有的 <w:t> 標籤。
    • 結論:在讀取純文字時,兩者效果完全一樣

3. 實戰比對:讀取樣式 (.style)

這裡就是「坑」的所在了。兩者回傳的資料型態完全不同。

程式碼範例

# --- 2. 讀取樣式 ---

# A. 使用 Paragraph (高層)
style_obj = p_obj.style
print(f"Paragraph 樣式型態: {type(style_obj)}") 
print(f"Paragraph 樣式名稱: {style_obj.name}")  # 例如: 'Heading 1'

# B. 使用 CT_P (底層)
style_id = ct_p.style
print(f"CT_P 樣式型態:      {type(style_id)}")
print(f"CT_P 樣式 ID:       {style_id}")        # 例如: '1'  'Heading1'
Python-docx 進階心法:穿梭於「表層 Paragraph」與「底層 CT_P」之間 - 儲蓄保險王

差異解析

  • Paragraph.style
    • 回傳的是一個 _ParagraphStyle 物件
    • 你可以透過它進一步存取字型、顏色等詳細設定 (style_obj.font.color...)。
    • 它顯示的是人類可讀的名稱 (如 “Heading 1”)。
  • CT_P.style
    • 回傳的是一個 字串 (String) (或者是 None)。
    • 這是 Word 內部使用的 Style ID (XML 屬性 w:val)。
    • 注意:Word 的內部 ID 常常跟顯示名稱不同!
      • 顯示名稱:”Heading 1″
      • 內部 ID:”1″ (或是 “Heading1″,取決於 Word 版本和語言)
      • 顯示名稱:”內文”
      • 內部 ID:可能為 None (代表預設樣式)

4. 總結與建議

Python-docx 進階心法:穿梭於「表層 Paragraph」與「底層 CT_P」之間 - 儲蓄保險王

什麼時候該用哪一個?

  1. 一般開發 (90% 的情況)
    請乖乖使用 Paragraph。它幫你處理了所有髒活,程式碼可讀性最高。
  2. 進階遍歷 (混合內容)
    當你需要依序讀取文件中的「段落」與「表格」時(因為 doc.paragraphs 會跳過表格),你必須遍歷 doc.element.body
    這時你拿到的都是 CT_P (段落) 或 CT_Tbl (表格)。
    • 在這種情況下,直接呼叫 body[i].text 是最乾淨俐落的寫法,不需要為了讀文字特地把它包裝回 Paragraph 物件。

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

加入好友
加入社群
Python-docx 進階心法:穿梭於「表層 Paragraph」與「底層 CT_P」之間 - 儲蓄保險王

儲蓄保險王

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

You may also like...

發佈留言

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