你需要了解的第一件事是XML命名空間。如果你有一些時間浪費,你可以閱讀the specification。我發現這是與XML有關的更清晰的規範之一。不要緊,如果你不明白它所說的一切,這是一個很好的基礎。但是這裏有一個快速的概要。
XML元素和屬性有一個名稱。當您看到<test att="hello"/>
時,您正在查看名稱爲「test」的元素,其中我們有一個名稱爲「att」的屬性。但這並不是真正的整個故事......
XML是一種語法,允許您混合來自不同標記語言的內容。例如,使用XSLT將XML文檔轉換爲XHTML頁面時,至少要處理三種以XML定義的標記語言:輸入文檔的XSLT和XHTML。如果每個人保留自己的元素/屬性名稱並且不允許任何衝突,那麼這種混合會變得相當困難。
輸入XML名稱空間。 XML名稱空間定義了一個「球體」,其中元素和屬性名稱具有實際的語義。元素「template」在XSLT名稱空間中有明確的含義。元素「complexType」在XML Schema名稱空間中有明確的含義。如果您希望以自己的標記語言使用XML,那麼可以在不同的名稱空間中這樣做。
爲了確保名稱空間是唯一的,您需要提供一些唯一標識符。規範以URI的使用爲基礎,最常見的形式是HTTP URL。原因很簡單:這些URL往往是很好的唯一標識符。但這也是導致混淆的一個常見原因,因爲人們認爲URL在XML處理過程中真正具有含義或將通過網絡訪問。 非常清楚,事實並非如此! URL不需要指向任何現有資源。它不會經過任何轉換或解析爲網絡地址。即使兩個URL指向完全相同的東西,但當它們相差一個字符時,它們被認爲是不同的名稱空間。名稱空間標識符只是一個字符串,並且區分大小寫。而已。
隨着名稱空間的引入,XML元素或屬性的名稱突然由兩部分組成:名稱空間和本地名稱。 <test/>
中的「測試」只是本地名稱。所謂的「完全限定名稱」由名稱空間和本地名稱的一種不可見組合組成。有時使用符號{namespace URI}local-name
,但這只不過是慣例而已。
所以現在我們需要能夠在XML文檔中使用名稱空間。爲了聲明一個名字空間,XML有一個硬編碼的機制。它使用特殊字符串xmlns
來允許進行名稱空間聲明。它可以通過兩種方式之一完成:將名稱空間綁定到前綴,或將其聲明爲默認名稱空間。
綁定到前綴時,表單是這樣的:xmlns:prefix="namespace URI"
。下面是一個XML文檔中的一個例子:
<foo:root xmlns:foo="http://www.foo.com">
<foo:test />
</foo:root>
現在我們已經綁定的命名空間http://www.foo.com
到前綴foo
。無論這個前綴放在元素或屬性名稱的前面,我們都會聲明它們是該名稱空間的一部分。
這裏需要注意的是,實際的前綴絕對沒有任何意義。以下XML文檔在語義上完全相同:
<bar:root xmlns:bar="http://www.foo.com">
<bar:test />
</bar:root>
前綴僅僅是一種表示命名空間的簡便方法。它使我們無需每次都使用URI。
接下來是默認的命名空間。默認名稱空間可以用xmlns="namespace URI"
來聲明。你可以抽象地認爲這是將一個名字空間綁定到空的前綴。再一次使用相同的XML文檔,但是這次沒有前綴:
<root xmlns="http://www.foo.com">
<test />
</root>
這樣處理起來更方便一些。那麼爲什麼要有前綴呢?當我們混合來自不同命名空間的內容時,它們開始扮演角色:
<root xmlns="http://www.foo.com">
<so:test xmlns:so="http://stackoverflow.com" />
</root>
這次它是一個不同的XML文檔。我們的root
元素位於http://www.foo.com
名稱空間中,但test
元素位於http://stackoverflow.com
中,因爲我們已綁定到so
前綴,並在test
上使用它。
您還會注意到,可以在XML文檔的任何元素上聲明名稱空間。該聲明的範圍(並且如果適用,則綁定到前綴)然後變成該元素及其內容。
這有時會變得令人困惑,甚至更多,因爲聲明可能互相覆蓋。查看此文檔:
<root xmlns="http://www.foo.com">
<test />
<so:test xmlns:so="http://www.stackoverflow.com" xmlns="http://www.bar.com">
<test />
</so:test>
</root>
花點時間弄清楚每個元素在哪個命名空間中......這是一個很好的練習。
root
在命名空間http://www.foo.com
中。第一個test
元素也位於該名稱空間中,因爲我們尚未使用前綴,但我們處於該默認名稱空間的範圍內。第二個test
元素的前綴爲so
位於命名空間http://www.stackoverflow.com
中,因爲這是我們將前綴綁定到的內容。
所以接下來是第三個最內層的test
元素。它是什麼名字空間?它沒有前綴,因此它必須位於默認名稱空間中。但是,我們已經改變了第二個測試元素中的默認命名空間!所以現在最裏面的元素屬於http://www.bar.com
命名空間,而不是http://www.foo.com
。
困惑了嗎?請記住以下幾點:
- 命名空間只是一個字符串。 URI用作具有唯一標識符的便捷方式。
- 前綴用於表示名稱空間,但其名稱不含任何含義。把它想象成一個佔位符。
- 您可以設置默認名稱空間。其範圍內沒有前綴的所有元素都將成爲它的一部分。
Phew。現在,到W3C XML Schema。所有這些與它有什麼關係?
那麼,對於初學者來說,XML Schema本身就是一種用XML定義的標記語言。所以它有理由說它有自己的命名空間。那個名字空間正式爲http://www.w3.org/2001/XMLSchema
。如果您將小寫字母S
寫出,那就錯了。開始明白爲什麼有些人真的討厭命名空間?
下列三個文件是完全一樣的:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</xsd:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
</xs:schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
</schema>
所有的事情是,我們正在使用的東西的XML架構命名空間。然而,按照慣例,人們傾向於在XML模式中使用前綴xs
或xsd
。
當我們有一個XML文檔時,我們可能希望指定它的模式所在的位置。不止一個模式可以與XML文檔相關,因爲正如我們所說的,語言可以在XML中混合使用。爲了說XML文檔是模式的一個實例,再次有一個特殊的命名空間可用:http://www.w3.org/2001/XMLSchema-instance
。按照慣例,我們傾向於將此名稱空間綁定到前綴xsi
。但是,這不是強制性的。
在該模式實例名稱空間中定義了一些屬性。其中有schemaLocation
和noNamespaceSchemaLocation
。看看這個文件:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.foo.com/schema">
</root>
那裏發生了什麼?首先我們聲明我們將前綴xsi
綁定到命名空間http://www.w3.org/2001/XMLSchema-instance
。然後我們使用該名稱空間內的屬性:noNamespaceSchemaLocation
。該屬性告訴我們模式的位置,以驗證文檔中不在任何特定名稱空間中的那些部分。以下XML文檔在語義上完全相同:
<root xmlns:huh="http://www.w3.org/2001/XMLSchema-instance" huh:noNamespaceSchemaLocation="http://www.test.com/schema">
</root>
請記住,前綴名稱沒有任何意義。他們是佔位符。那麼,那noNamespaceSchemaLocation
屬性是什麼?基本上,它告訴我們我們可以在哪裏找到一個模式。現在,與名稱空間URI相反,這絕對是可以用來從網絡或本地存儲中獲取內容的東西。針對在文檔中聲明的模式進行驗證的XML處理器可能會嘗試獲取它。
然後有一個事實,它被稱爲noNamespaceSchemaLocation
。模式定義了「目標名稱空間」。它所做的是聲明它定義的元素和屬性是哪個名稱空間的一部分。但是目標命名空間可能被省略。在這種情況下,我們得到了一個沒有命名空間的XML文檔模式。這種模式可以參考noNamespaceSchemaLocation
。
在很多情況下,模式實際上會定義一個名稱空間。爲了說哪個模式屬於哪個命名空間,我們可以使用http://www.w3.org/2001/XMLSchema-instance
命名空間的另一個屬性:schemaLocation
。該屬性可以包含名稱空間URI和模式URI的對(由空格分隔)。假設我們有位於http://www.myschemas.com/foo-schema
的名稱空間http://www.foo.com
的模式。然後,我們可以說,如下:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.foo.com http://www.myschemas.com/foo-schema">
</root>
這裏有多個命名空間位置對一個例子:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.foo.com http://www.myschemas.com/foo-schema http://www.bar.com http://www.randomschemas.com/bar-schema">
</root>
你需要在這裏記住的是,http://www.w3.org/2001/XMLSchema-instance
東西是用在那些XML文檔模式的實例。名稱空間http://www.w3.org/2001/XMLSchema
是用於自己定義模式的名稱空間。
所以現在我們達到我們的URI和具有特殊含義看起來怪怪的屬性脖子。這是命名空間的事情:它們看起來非常複雜,直到你弄清楚它們是多麼簡單。只要密切關注哪些前綴綁定了哪些名稱空間URI,並知道該URI定義了什麼。
還有兩件事情需要解決您的問題:xs:import
和xs:include
。注意我在這裏使用了xs
前綴約定,因爲我們正在討論W3C XML Schema。
include元素可用於將模式與相同的目標名稱空間結合使用。基本上它允許我們將模式模塊化成更小的部分並將它們放在一起。
導入元素確實排序相同,但對於具有不同目標命名空間的模式。這使我們可以將模式組合爲不同的標記語言。
因此,要回顧:
xmlns
:用來指定一個默認的命名空間。
xmlns:prefix
:用於將命名空間綁定到prefix
。
http://www.w3.org/2001/XMLSchema
:XML架構的名稱空間。根據約定,通常綁定在前綴xs
,但這不是強制性的,也不是自動完成的。
http://www.w3.org/2001/XMLSchema-instance
:這個命名空間定義了一些對於聲明XML文檔是如何作爲模式實例的細節有用的東西。根據約定,通常綁定在前綴xsi
,但這不是強制性的,也不是自動完成的。
targetNamespace
:可用於XML架構(在根元素上)的屬性,用於指定哪個名稱空間是模式定義。
schemaLocation
:由名稱空間http://www.w3.org/2001/XMLSchema-instance
定義的屬性之一,用於指示可以爲一個或多個名稱空間找到一個或多個模式的位置。
我最終的建議:找到一些方便的方法來驗證文檔對抗模式並玩一下。嘗試命名空間,包括和導入。使用多個名稱空間創建文檔並嘗試範圍界定。
之後,檢查XML本身,XML名稱空間和XML Schema的規範。這是硬核閱讀,但如果你通過它的方式,你會得到一個理解,許多人仍然似乎錯過多年的XML使用。最終它都會有意義。
祝你好運!
這是史詩 - 應該是這類問題的權威答案,如果堆棧溢出支持此功能。感謝張貼這個我學到了很多東西,可以看到我的答案確實有限的原因。 –
@hugh它甚至不完整...對於屬性,前綴有一些偏離規則。他們默認情況下不合格。但我不完全確定是否將它們放入元素的名稱空間中,因此我非常小心地對其進行說明。還有更多我可以提到的東西,但事實是隻有規格才能提供明確的答案。 –
G_H很少有人花時間回答這個問題。謝謝! – IAmYourFaja