過去一年多裡 docutils 已經成為我最喜歡的排版工具,本部落格大部分的文章也都是用 docutils 輸出的。但 docutils 還是有無法盡如人意之處,其中最主要的問題在於所產生的 HTML 和我部落格原本的 CSS 並不相容,例如 docutils 通常用 class 來指定樣式,但是我既有的策略恰好希望文章內容不要用 class selector。其次是 docutils 生成的 HTML 對於部落格來說頗為累贅,例如標題和區段會輸出成:

<h1>ooxx</h1>
<div class="section" id="ooxx">

以部落格來說,我覺得根本沒必要為區段建立 div。其他比較無所謂的問題還包括:docutils 並未嚴格遵循 HTML Strict、使用將被廢棄的 <tt> 標籤等等。

原本我的方法就是在 docutils 輸出之後,額外執行一小段我寫的過濾程式,把政治不正確的字串替換掉。但當要改的東西多起來時,這個做法顯得很醜,而且遇到超出 regular expression 表達力的字串就頭大了。

要從根本解決問題其實不難,只要改寫 docutils 的 writers 即可。其中 HTML writer 位在[python_dir]\Lib\site-packages\docutils\writers\html4css1之下,快速瞄一下大概就知道他的工作原理了。

接下來不必直接對程式庫作侵入式修改,比較好的做法是建立一個新的 python 程式,繼承 html4css1.Writer 和 html4css1.HTMLTranslator,只改寫我們需要的功能,然後呼叫 publish 函數。架構如下:

from docutils.writers import html4css1
from docutils import nodes

class MyBlogWriter(html4css1.Writer):
    def __init__(self):
        html4css1.Writer.__init__(self)
        self.translator_class = MyBlogTranslator

class MyBlogTranslator(html4css1.HTMLTranslator):
    def visit_XXX(self, node):
        ...

    def depart_XXX(self, node):
        ...


try:
    import locale
    locale.setlocale(locale.LC_ALL, '')
except:
    pass

from docutils.core import publish_cmdline, default_description


description = ('Generates XHTML for my blog.'
                + default_description)

publish_cmdline(writer=MyBlogWriter(), description=description)

每個文件樹結點 X 都會有對應的 visit_X、depart_X 函數,我們可以從這裡下手改寫 HTML 標籤產生規則。例如前述的 section 對應的函數為

def visit_section(self, node):
    self.section_level += 1
    self.body.append(self.starttag(node, 'div', CLASS='section'))

def depart_section(self, node):
    self.section_level -= 1
    self.body.append('</div>\n')

另外輔助函式 should_be_compact_paragraph() 影響某些元素會不會用 <p> 包圍,HTML Strict 對此要求比較嚴格,預設的 docutils HTML Writer 並不滿足 HTML Strict 的標準。如果有興趣的話還可以做更進階的功能,像是在 literal block 裡面,我們可以用 node.astext() 取得文字內容,找出關鍵字加上 highlight。實作可以參考 visit_literal。(我知道這個功能老早就被 sphinx 等完成了)

Odt Writer 原理也差不多,只差在他的輸出是 OpenOffice XML,我比較沒有研究。

希望以上內容對於其他 docutils 使用者有所幫助,官網對此著墨並不多,在動手之前可以參考這裡的背景知識:

Docutils Hacker's Guide

Inside A Docutils Command-Line Front-End Tool

The Docutils Publisher

novus 發表在 痞客邦 PIXNET 留言(0) 人氣()