我正在開發一個 Node.js 應用程式,它接收一個 XHTML 片段(Confluence 存盤格式),應該對其進行一些修改,然后發回修改后的 XHTML。XHTML 可能包含 HTML 物體(例如ö)和 CDATA 部分(例如<![CDATA[test]]>)。
我遇到的挑戰是,使用我嘗試過的決議器,當我在 HTML 模式下決議代碼段時,CDATA 部分會中斷,但是當我在 XML 模式下決議它時,HTML 物體沒有被正確解釋。
下面是我如何讓它在瀏覽器中作業的一個例子,但是我如何使用 jsdom 和cheerio 讓它作業。是否有任何其他庫可以用來實作這一點,或者使用 jsdom 或cheerio 的任何不同方式?
在瀏覽器中
在瀏覽器中,我可以DOMParser在 XML 模式下作業。使用測驗片段<span>ö<![CDATA[?]]></span>,我可以將它包裝在 XHTML 正文中:
const doc = new DOMParser().parseFromString(`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body><span>ö<![CDATA[?]]></span></body></html>`, 'application/xml');
doc.querySelector('body').innerHTML; // <span>?<![CDATA[?]]></span>
doc.querySelector('body').textContent; // ??
XML MIME 型別確保正確解釋 CDATA 部分,而 XHTML DOCTYPE 確保支持物體。
jsdom
為了在 Node.js 中實作相同的目標,我嘗試使用jsdom。問題是,當我在 HTML 模式下決議代碼時,CDATA 部分被轉換為注釋,但是當我在 XML 模式下決議它時,由于 HTML 物體而引發例外:
import { JSDOM } from 'jsdom';
const xhtml = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body><span>ö<![CDATA[?]]></span></body></html>`;
new JSDOM(xhtml).window.document.body.innerHTML; // <span>?<!--[CDATA[?]]--></span>
new JSDOM(xhtml).window.document.body.textContent; // ?
new JSDOM(xhtml, { contentType: 'application/xml' }); // Uncaught DOMException [SyntaxError]: about:blank:1:186: undefined entity.
更新:我已經向 jsdom報告了這個問題。
啦啦隊
我更喜歡在后端進行 DOM 修改的方法是Cheerio。在 HTML 模式下使用cheerio,CDATA 部分被轉換為注釋。在 XML 模式下,物體不會被解釋,而是被雙重轉義為&ouml;. 在沒有解碼物體的 XML 模式下,XHTML 被正確保留,但物體沒有被正確解釋,這在獲取文本內容時可以看到。
import cheerio from 'cheerio';
const xhtml = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body><span>ö<![CDATA[?]]></span></body></html>`;
cheerio.load(xhtml).root().find('body').html(); // <span>?<!--[CDATA[?]]--></span>
cheerio.load(xhtml).root().find('body').text(); // ?
cheerio.load(xhtml, { xmlMode: true }).root().find('body').html(); // <span>&ouml;<![CDATA[?]]></span>
cheerio.load(xhtml, { xmlMode: true }).root().find('body').html(); // ö?
cheerio.load(xhtml, { xmlMode: true, decodeEntities: false }).root().find('body').html(); // <span>ö<![CDATA[?]]></span>
cheerio.load(xhtml, { xmlMode: true, decodeEntities: false }).root().find('body').text(); // ö?
更新:我已將問題報告給了cheerio。
uj5u.com熱心網友回復:
有人向我指出了Cheerio 中該問題的解決方法:
cheerio.load(xhtml, { xml: { xmlMode: false, recognizeCDATA: true, recognizeSelfClosing: true } });
使用這些選項,我可以在 Node.js 環境中成功決議 XHTML。
除了這個解決方案,我注意到DOMParser在瀏覽器中使用 的缺點是瀏覽器之間存在不一致。特別是,當將查詢選擇器與 XML 名稱空間結合使用時,我有時不得不在查詢中包含名稱空間,有時則不需要。由于這些不一致,jquery 也正式不支持 XML 命名空間。為了在瀏覽器之間以及前端、前端測驗和后端之間實作一致的行為,我決定甚至使用cheerio 來決議瀏覽器中的XHTML。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/341505.html
標籤:javascript 节点.js dom html
