本系列的前一篇文章講述了HTML實體編碼(10進制、16進制)與字符的相互轉換,本文將講述HTML命名實體與字符的相互轉換,如<
轉義成<
。你可能想問我爲什麼兩篇文章間隔了約三個月,其實我本來沒想續寫,但是之前因爲沒寫到命名實體,所以總感覺不完美,而且最近又想起了這個問題,於是準備寫個解決方案,來彌補遺憾。好了,準備言歸正傳。PS:如有錯誤,請不吝指正。
1. 字符轉爲html命名實體
針對這個問題,可以分爲兩種情況:一種是隻包含&、<、>、'
的html實體,另一種是廣義的實體,不只侷限於上面的情況。對於後者,在我看來,除了列舉出所有的實體符號,寫switch case語句,還真的沒有什麼好辦法。(如果您有什麼好辦法,請不吝賜教。)。針對前者的話,其實原生js就支持。例如會自動對文本中存在的HTML語法字符(小於號、大於號、引號及和號)進行編碼的節點的innerText
屬性(FireFox中是textContent
屬性。實際上二者並不完全一樣,innerText會忽略行內樣式和腳本,而textContent則會原樣返回行內樣式和文本。)。其原理是設置innerText會生成當前節點的一個子文本節點,而爲了確保只生成一個子文本節點,就需要對文本進行HTML編碼。innerHTML雖然也可以做到,但它轉變的只是標籤的文本。下面的例子展示了它們的不同。
var div=document.createElement('div');
div.innerText='<p>hello & world</p>';
div.innerText //<p>hello & world</p>"
div.innerHTML //"<p>hello & world</p>"
div.innerHTML='<p>hello & < world</p>'
div.innerHTML //"<p>hello & < world</p>"
div.innerText //"hello & < world"
從上面例子中可以看到二者的區別:innerText
會將所有的文本轉義(當然也不是全部文本,比如空格就不會),innerHTML
則是對標籤內的文本進行轉義,標籤如<p>
就不會轉義,但孤立的小於大於號還是會進行轉換的。(上面代碼中innerHTML
之所以設置的內容和解析後的內容不一樣,是因爲返回的是瀏覽器根據原始字符串解析爲DOM樹後經過序列化之後的結果。)根據上面程序的結果,我們可以得到簡單的轉換函數:
//僅限於包含`&、<、>、'`的文本轉換
function stringToEntity(str){
var div=document.createElement('div');
div.innerText=str;
div.textContent=str;
var res=div.innerHTML;
console.log(str,'->',res);
return res;
}
其實除了innerText
,還可以通過創建文本節點的方式來完成轉義,即使用document.createTextNode()
。這種方法大部分的應用場景是對用戶輸入進行轉義。例如業務需要,我們需要把用戶的輸入寫到網頁上,不做轉義直接將用戶輸入寫到網頁上往往是行不通的,因爲容易出現XSS漏洞。不過我們可以通過document.createTextNode()
方法將用戶輸入作爲文本節點,然後再插入到文檔中。該方法會對出現的特殊標記進行轉義。例如如下代碼:
var str="<img src='a valid url' onload='alert(1)'></img>";
var text=document.createTextNode(str);
$("container").appendChild(text);
上述代碼中如果不加轉義直接使用$("container").innerHTML=str;
就會使得圖片加載完運行onload
裏面的代碼,如果代碼是惡意的,就會爲我們網站的用戶造成損害。而將小於號、大於號轉義後就不會出現這個問題了。
2. html命名實體轉換爲字符
雖然不能直接寫出字符轉換爲html實體的簡單程序,但是寫出字符轉換爲html實體的程序還是可以的。如以下代碼:
function entityToString(entity){
var div=document.createElement('div');
div.innerHTML=entity;
var res=div.innerText||div.textContent;
console.log(entity,'->',res);
return res;
}
//test
entityToString('<hello world>')
//output: <hello world> -> <hello world>
//output: "<hello world>"
將輸入的實體符號賦值給div.innerHTML
,通過div.innerText
或div.textContent
取出即可得到轉義後的文本。
好了,以上就是我想和大家分享的內容。