注:本文翻譯自developer.mozilla.org/en/docs/Web/SVG/Namespaces_Crash_Course 暂吉。是在自己的理解的基礎(chǔ)上翻譯的,如果有疑義可以自己看英文版肮街。
作為XML 的一個(gè)方言,SVG 需要在一個(gè)命名空間內(nèi)(is namespaced)判导。理解命名空間的概念嫉父,以及在你打算編輯SVG內(nèi)容時(shí),命名空間如何使用眼刃,是很重要的绕辖。SVG查看器的版本早于Firefox 1.5的發(fā)布的,都幾乎沒有注意命名空間的問題擂红,但它們對(duì)于支持多XML方言的用戶代理(如基于Gecko的瀏覽器)必不可少仪际,這些瀏覽器對(duì)這些也有非常嚴(yán)格的要求。花一些時(shí)間來了解命名空間树碱,它會(huì)為您節(jié)省各種各樣的頭痛肯适。
1、背景
W3C的長期目標(biāo)是使不同類型的基于XML的內(nèi)容能夠在同一個(gè)XML文件中混合使用。例如,SVG和MathML可以直接并入基于XHTML的科學(xué)文檔中额港。能夠混合這些不同的內(nèi)容類型具有許多優(yōu)點(diǎn)绢馍,但是它還需要解決一個(gè)實(shí)際的問題瓷耙。
??自然地,每種XML方言定義其規(guī)范中描述的標(biāo)記標(biāo)簽名稱的含義。在單個(gè)XML文檔中混合來自不同XML方言的內(nèi)容的問題是由一種方言定義的標(biāo)記標(biāo)簽可能會(huì)有與由另一種方言定義的標(biāo)記標(biāo)簽相同的名稱谁尸。例如背镇,XHTML和SVG都有一個(gè)<title>標(biāo)簽涮总。用戶代理應(yīng)該如何區(qū)分兩者?
??事實(shí)上,用戶代理什么時(shí)候能夠識(shí)別XML內(nèi)容,而不只是一個(gè)包含許多無法識(shí)別的標(biāo)簽的XML文件?與大眾意見相反,這個(gè)問題的答案不是“它可以從DOCTYPE聲明”蛤克。DTD從未設(shè)計(jì)過混合內(nèi)容撬码,過去嘗試創(chuàng)建混合內(nèi)容DTD現(xiàn)在被認(rèn)為已失敗。XML和一些XML方言(包括SVG),不需要DOCTYPE聲明森篷,SVG 1.2甚至不會(huì)有一個(gè)钓辆。 DOCTYPE聲明(通常)匹配單個(gè)內(nèi)容類型文件中的內(nèi)容的事實(shí)僅僅是巧合的似嗤。DTD僅用于驗(yàn)證顽馋,而不是內(nèi)容的識(shí)別属桦。用戶代理使用其DOCTYPE聲明偽裝和識(shí)別XML內(nèi)容是沒有作用的系谐。
??這個(gè)問題的真正答案是茶袒,XML內(nèi)容通過給標(biāo)簽顯式的“命名空間聲明”告訴用戶代理標(biāo)記名稱屬于哪個(gè)方言。
2、聲明命名空間
那么這些命名空間聲明是什么樣子,聲明在哪里睡毒?這里是一個(gè)簡短的例子。
<svg xmlns="http://www.w3.org/2000/svg">
<!-- more tags here -->
</svg>
命名空間聲明由xmlns屬性提供涕蚤。此屬性表示<svg>標(biāo)記及其子標(biāo)記屬于名稱空間為“http://www.w3.org/2000/svg”的XML方言,當(dāng)然扰她,它是SVG艇拍。注意个初,命名空間聲明只需要在根標(biāo)記上提供一次谆膳。聲明定義了默認(rèn)命名空間祝迂,因此用戶代理知道所有<svg>標(biāo)簽的后代標(biāo)簽也屬于同一命名空間。用戶代理檢查他們是否屬于同一個(gè)命名空間,如果是的話才去如何處理命名空間下的標(biāo)簽標(biāo)記乌妒。
??注意古掏,命名空間名稱只是字符串,盡管SVG命名空間名稱看起來像URI忘闻,但這并不重要重虑。URI通常被使用,因?yàn)樗鼈兪俏ㄒ坏囊彀康牟皇恰版溄印蹦程幋蹩唷#ㄊ聦?shí)上??青伤,URI經(jīng)常使用,通常使用術(shù)語“命名空間URI”而不是“命名空間名稱”暂氯。)
3潮模、重新聲明默認(rèn)命名空間
因此,如果根標(biāo)記的所有后代也被定義在默認(rèn)命名空間中痴施,那么如何混合來自另一個(gè)命名空間的內(nèi)容擎厢?簡單。您只需重新定義默認(rèn)命名空間辣吃。這里有一個(gè)簡短的例子动遭。
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<!-- some XHTML tags here -->
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
<!-- some SVG tags here -->
</svg>
<!-- some XHTML tags here -->
</body>
</html>
在此示例中,根<html>標(biāo)簽上的xmlns屬性將默認(rèn)名稱空間聲明為XHTML神得。因此厘惦,除了<svg>標(biāo)記,用戶代理將其及其所有子標(biāo)記解釋為屬于XHTML哩簿。 <svg>標(biāo)記具有自己的xmlns屬性宵蕉,通過重新聲明默認(rèn)命名空間,這告訴用戶代理节榜,<svg>標(biāo)記及其后代(除非他們也重新編寫默認(rèn)命名空間)屬于SVG羡玛。看宗苍,命名空間真的不是那么難稼稿。
4、聲明命名空間前綴
XML方言不僅定義自己的標(biāo)簽讳窟,而且定義自己的屬性让歼。默認(rèn)情況下,屬性根本沒有命名空間丽啡,并且只知道是唯一的谋右,因?yàn)樗鼈兂霈F(xiàn)在本身具有唯一名稱的元素上。然而碌上,有時(shí)需要定義屬性倚评,使得它們可以在許多不同的元素上重用,并且仍然被認(rèn)為是相同的屬性馏予,與它們所使用的元素?zé)o關(guān)天梧。一個(gè)很好的例子是由XLink規(guī)范定義的href屬性。此屬性通常被其他XML方言用作鏈接到外部資源的手段霞丧。但是如何告訴用戶代理該屬性屬于哪個(gè)方言呢岗,在這種情況下用“XLink”?請(qǐng)考慮以下示例。
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script xlink:href="cool-script.js" type="text/ecmascript"/>
</svg>
這個(gè)例子有相當(dāng)不尋常的看起來的屬性xmlns:xlink后豫。正如你可能從第一個(gè)“xmlns”部分猜到的悉尾,這是另一個(gè)命名空間聲明。然而挫酿,這個(gè)命名空間聲明不是設(shè)置默認(rèn)命名空間构眯,而是設(shè)置稱為“命名空間前綴”的命名空間。在這種情況下早龟,我們選擇使用前綴xlink(第二部分)惫霸,因?yàn)榍熬Y將用于告訴用戶代理屬于XLink的屬性。
??顧名思義葱弟,命名空間前綴用于前綴屬性名稱和標(biāo)簽名稱壹店。這是通過在屬性名稱之前放置命名空間前綴和冒號(hào)來實(shí)現(xiàn)的,如上例中的<script>標(biāo)記所示芝加。這告訴用戶代理該特定屬性屬于分配給命名空間前綴(XLink)的命名空間硅卢,并且它是可以用于具有相同含義的其他標(biāo)記上。
??請(qǐng)注意藏杖,使用未綁定到命名空間名稱前綴是XML錯(cuò)誤将塑。盡管xlink:href屬性不會(huì)導(dǎo)致錯(cuò)誤,但上面示例中由xmlns:xlink屬性創(chuàng)建的綁定是絕對(duì)必要的蝌麸。這個(gè)XLink屬性在SVG中經(jīng)常在<a>抬旺,<use>和<image>標(biāo)簽等中使用,所以最好在文檔中始終包含XLink聲明祥楣。
??另外,命名空間前綴也可以用于標(biāo)記名稱汉柒。這告訴用戶代理误褪,這個(gè)特定的標(biāo)簽(但不是它的孩子這一次!)屬于分配給前綴的命名空間碾褂。知道這些將減少你一些迷惑兽间,如果你遇到了像下面的例子中的標(biāo)記:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:svg="http://www.w3.org/2000/svg">
<body>
<h1>SVG embedded inline in XHTML</h1>
<svg:svg width="300px" height="200px">
<svg:circle cx="150" cy="100" r="50" fill="#ff0000"/>
</svg:svg>
</body>
</html>
請(qǐng)注意,因?yàn)槊Q空間前綴用于<svg:svg>標(biāo)記及其子<svg:circle>正塌,因此無需重新聲明默認(rèn)名稱空間嘀略。一般來說,最好重新聲明默認(rèn)名稱空間乓诽,而不是以這種很多前綴標(biāo)簽的方式帜羊。
5、聲明命名空間前綴使用命名空間XML編寫腳本
命名空間不僅影響標(biāo)記鸠天,還影響腳本讼育。如果您編寫用于命名空間的XML(如SVG)的腳本,請(qǐng)繼續(xù)閱讀。
??DOM1級(jí)別推薦在XML的原始命名空間發(fā)布之前創(chuàng)建; 因此奶段,DOM1不是命名空間所識(shí)別的饥瓷。這會(huì)導(dǎo)致名稱空間的XML(如SVG)出現(xiàn)問題。為了解決這些問題痹籍,DOM2級(jí)別添加了命名空間的所有適用的DOM1方法呢铆。當(dāng)編寫SVG腳本時(shí),使用命名空間能識(shí)別的方法很重要蹲缠。下表列出了不應(yīng)在SVG中使用的DOM1方法棺克,以及應(yīng)該使用的等效DOM2對(duì)等方法。如下圖:
所有DOM2命名空間方法的第一個(gè)參數(shù)必須是有問題的元素或?qū)傩缘拿臻g名稱(也稱為命名空間URI)吼砂。對(duì)于SVG元素逆航,這是“http://www.w3.org/2000/svg”。 但是渔肩,請(qǐng)注意:XML 1.1中的命名空間建議指出因俐,沒有前綴的屬性的命名空間名稱沒有值。換句話說周偎,雖然屬性屬于標(biāo)簽的命名空間抹剩,但不使用標(biāo)簽的命名空間名稱。相反蓉坎,您必須使用null作為未限定(無前綴)屬性的命名空間名稱澳眷。 因此,要使用document.createElementNS()創(chuàng)建一個(gè)SVG rect元素蛉艾,您必須寫:
document.createElementNS('http://www.w3.org/2000/svg', 'rect');
但是要檢索SVG rect元素上的x屬性的值钳踊,必須寫:
rect.getAttributeNS(null, 'x');
注意,不是針對(duì)具有命名空間前綴的屬性(屬于與標(biāo)記不屬于同一個(gè)XML方言的屬性)的情況勿侯。諸如xlink:href屬性的屬性需要分配給該前綴的命名空間名稱(對(duì)于XLink拓瞪,請(qǐng)使用http://www.w3.org/1999/xlink)。 因此助琐,要獲取SVG中<a>元素的xlink:href屬性的值祭埂,您應(yīng)該寫:
elt.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
對(duì)于設(shè)置具有命名空間的屬性,建議(但不是必需)兵钮,您還在第二個(gè)參數(shù)中包括其前綴蛆橡,以便以后可以更容易地將DOM轉(zhuǎn)換回XML(如果您想要將其發(fā)送回 服務(wù)器)。 例如:
elt.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'otherdoc.svg');
作為最后一個(gè)例子掘譬,這里是一個(gè)演示如何使用腳本動(dòng)態(tài)創(chuàng)建一個(gè)<image>元素:
var SVG_NS = 'http://www.w3.org/2000/svg';
var XLink_NS = 'http://www.w3.org/1999/xlink';
var image = document.createElementNS(SVG_NS, 'image');
image.setAttributeNS(null, 'width', '100');
image.setAttributeNS(null, 'height', '100');
image.setAttributeNS(XLink_NS, 'xlink:href', 'flower.png');
6泰演、總結(jié):
確保您始終聲明您在XML文件中使用的命名空間。 如果不這樣做葱轩,F(xiàn)irefox等用戶代理將無法識(shí)別您的內(nèi)容粥血,只會(huì)顯示XML標(biāo)記或通知用戶XML中有錯(cuò)誤柏锄。 在創(chuàng)建新的SVG文件時(shí),最好使用包含所有常用命名空間聲明的模板复亏。 如果你還沒有一個(gè)趾娃,請(qǐng)從下面的代碼開始:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>
即使您不在特定文檔中使用所有這些命名空間,包含命名空間聲明也沒有任何危害缔御。 如果你在以后添加來自一個(gè)未使用的命名空間的內(nèi)容抬闷,它可以避免一些惱人的錯(cuò)誤。