資深網頁人員應該都看過這種風格的 HTML:

這類 HTML 多半來自 Word 等 Office 軟體,特徵包含:

  • p 一律掛了 class="MsoNormal" 但 MsoNormal 樣式規則不存在
  • 無所不在 style="font-family: 新細明體, serif;"style="margin-bottom: 18.0pt; text-indent: 24.0pt;"... 明明可以用階層關係或 class="" 規則大幅簡化,但 Office 沒在計較這些雞毛蒜皮小事,遍地開花,加好加滿
  • 中文字串夾雜的英數字時會特別用 <span lang="EN"></span> 包夾

一般來說,這些多餘 HTML 屬性標籤無傷大雅,不影響閱讀。但我想擷取轉電子書自用,一時龜毛,想把 HTML 整理到清爽一點:

清理邏輯的構想如下:

  1. 去除到處出現的 style="font-family: 新細明體, serif;" 樣式,一來細明體太醜,二則既然是相同字型,在 body 設定一次即可
  2. 移除所有 <span lang="EN">,將其中包含內容提取到上一層,這裡會用到取得文字節點的技巧
  3. 移除完全無用的 class="MsoNormal"
  4. 掃瞄所有 style="..."內容,提取 margin-bottom: 18.0pt、font-size: medium 轉成 s1, s2, s3... 樣式規則(自動跳號),元素端簡化為 class="s1 s5"

這個構想要實作不難,但如何用最簡潔的程式碼實現呢?

招喚老戰友 jQuery,先花 10 行動態載入 jquery-3.6.4.slim.min.js,處理邏輯不到 35 行搞定,不愧是 jQery!

let sc = document.createElement('script');
sc.src = 'https://code.jquery.com/jquery-3.6.4.slim.min.js';
document.body.appendChild(sc);

let h = setInterval(function () {
    if (typeof $ !== 'undefined') {
        clearInterval(h);
        clean();
    }
}, 100);

function clean() {
    let styles = {};
    let ignoreFont = 'font-family: 新細明體, serif;';
    $('span').each(function () {
        let s = $(this);
        if (s.attr('lang') == 'EN-US') s.replaceWith(s.contents());
        s.attr('style', (s.attr('style') || '').replace(ignoreFont, ''));
        if (!s.attr('style')) s.replaceWith(s.contents());
    });
    let cssIdx = 0;
    let cssDict = {};
    $('p,div,span').each(function () {
        let p = $(this);
        p.removeClass('MsoNormal');
        if (!p.attr('style')) return;
        let parts = p.attr('style').split(';');
        parts.forEach(t => {
            if (!t) return;
            if (!cssDict[t]) {
                cssDict[t] = 's' + cssIdx;
                cssIdx++;
            }
            p.addClass(cssDict[t])
        });
        p.attr('style', null);
    });
    let rules = [];
    for (let t in cssDict) {
        rules.push('.' + cssDict[t] + ' { ' + t + '; }');
    }
    let cssBlock = document.createElement('style');
    cssBlock.innerHTML = rules.join('\n');
    document.body.appendChild(cssBlock);    
}

當屠龍刀用了十幾年仍削鐵如泥,硬要嫌兵器重棄如蔽屣,豈不是為難自己?依場合選擇最順手的武器,因時因地制宜,方為明智之舉。

再戰十年吧,jQuery!

延伸閱讀:從「鄙視 jQuery」聊起 -技術鄙視從何而來?

【2023-04-03 更新】

Example of cleaning up redundant HTML attributes and tags with jQuery.


Comments

Be the first to post a comment

Post a comment