一、命名空間的意義
XML 是一種非常好用的標記語言,它具有極好的可擴展性,因此當我們需要同時訪問多份 XML 文檔時,有可能會出現這樣一種情況:在同一份 XML 文檔中可能出現多個同名的標簽和屬性,而這些標簽和屬性意義又是完全不同的,遇到這種情況如果我們如果不從語法上提供區別,則XML處理器將無法區分它們。
為了解決這個問題 XML 提供了命名空間的支持。我們想象這樣一個場景,在學校的操場上你喊一句"小明"可能一下子會有好幾個小明回應你。那你如果喊 3 年級 2 班的小明,那可能只會有你找的那個小明回應你。這里我們指定了一個范圍(3年級2班),在這個范圍內小明是唯一的。說簡單一些,要確定一個人僅有名字是不夠的,還必須要有一個確定的范圍,這個范圍就可以理解為命名空間。
回到 XML 中,假如有這樣一個文檔,文檔中需要保存圖書的信息,同時有包含作者的詳細信息,可以能會是如下一個文檔:
<book>
<title>西游記</title>
<author>
<name>吳承恩</name>
<title>先生</title>
</author>
</book>
這個文檔中 book 有兩個子標簽 title 和 author ,title 表示書名,author 表示作者的信息。而 author 中也有一個 title 屬性,這里 title 只的是頭銜稱呼,也就是表示的是稱吳承恩為先生,但是這里 book 中的 title 和 author 中的 title 確是兩個完全不同的意思,僅僅靠程序是不能區分開這兩個 title 的含義的.
二、使用前綴
解決這個問題最好的方法就是為不同的元素起不同的名字。比如:這里我們可以定一個規則,每一個 book 下的元素使用一個前綴,而 author 下的使用另一個前綴,這樣我們可以通過不同的前綴來區分不同的標簽,如此一來我們的文檔會變成這個樣子:
<b:book>
<b:title>西游記</b:title>
<a:author>
<a:name>吳承恩</a:name>
<a:title>先生</a:title>
</a:author>
</b:book>
這種方式看起來比較難看,但是確實可以達到區分的目的,現在 b:title 和 a:title 就是兩個不同的標簽。
通過前綴名我們可以很方便的將文檔中的標簽分成兩類 a 和 b,帶有前綴 a 的屬於 a 類型,帶有前綴 b 的屬於 b 類型,這個類就是命名空間,這里你看起來是不是和 Java 中的包名有着異曲同工的效果呢?
但是這里還存在一個小問題,這里的命名空間還只是通過名字來區分不同的標簽,也就是說命名空間只是為名字進行了一個分類但是名字具體代表了什么意義,它們應該在哪里出現,它並沒有一個說明和約束(這里就要涉及到 XML 的約束文檔了,.xsd 或 schemal 文件).
三、為什么XML沒有直接使用前綴
我們上邊這個方法可以解決我們所面臨的問題,但是 XML 為什么沒有直接采用這種方式呢?因為這種方式存在一個漏洞,我們通過前綴來約束標簽名,那么前綴是否有可能重復呢?加入一份有 atguigu定義的 XML 文檔,前綴我們設置為 a。這里又一份 alibaba 定義的文檔前綴同樣為 a,那這兩份文檔是不是就會出現重復的標簽呢?所以我們的問題並沒有根本解決。
解決這個問題現在變成了我們需要使用一個唯一的前綴來確保文檔中標簽的唯一性,那么現實中有哪些東西是唯一的呢?想一下,java 中包名采用的是哪種方式?沒錯!就是 uri 地址,java 中通過將uri 地址倒着寫來到達區分包的目的,之所以可行就是因為每個公司的 uri 地址都是唯一的,所以不會出現重復。
這里我們就可以為我們的標簽名使用 uri 地址作為前綴比如 (http://www.atguigu.com/a)title,采用這種方式很顯然出現重復的幾率就小多了,但是注意這里的 http://www.atguigu.com/a並不是一個真實的地址,它的目的就是一個確保唯一。
這種方式雖然看着可行但是實際上是不現實的,不討論 XML 中可不可以直接在標簽中編寫 uri 地址,僅從編寫的角度上看我們也不會這個干,這玩意太麻煩了,誰會去寫一個這樣的標簽啊
<author:http://www.atguigu.com ..... />
四、XML中如何使用命名空間
XML 命名空間為我們提供了一個標准的語法,聲明 XML 名稱空間,並為 XML 文檔里的某個元素確定命名空間。
要在文檔里使用 XML 命名空間,元素名就變成了限定名(qualified names 縮寫為 qName),限定名分成了兩部分,一部分就是我們之前使用的元素名;另一部分是命名空間的前綴,它確定了這個名稱所在的命名空間。
<b:book xmlns:b="http://www.atguigu.com/xml/b">
我們在根標簽中添加了一個 xmlns:b 屬性,xmlns 代表的是 xml namespace,b 是我們聲明的命名空間前綴,b本身並沒有意義,可以將它理解為是 http://www.atguigu.com/xml/b 的一個別名,我們在標簽中使用 b,就相當於使用這個 uri 地址。一旦使用了 b 這個前綴,就代表這個標簽是屬於 http://www.atguigu.com/xml/b 這個唯一標識命名空間下的元素。
我們還可以在一個文檔中定義多個命名空間,如下的語法也是沒有問題的:
<b:book xmlns:b="http://www.atguigu.com/xml/b"
xmlns:a="http://www.atguigu.com/xml/a">
五、默認的命名空間
這樣我們在文檔中就可以使用 a 和 b 兩個前綴來區分不同的命名空間中的標簽了。但是實際上咱們所使用的前綴並不友好,為了方便識別在開發中盡量使用便於識別的前綴,比如 book,author 等。
采用以上的方式聲明命名空間已經可以很好的解決了咱們的問題,但是這種方式顯得有一些麻煩,因為每一個標簽都需要加上一個前綴,不如直接寫標簽名來的爽快。所以 XML 還給我們提供了一種方式可以聲明一個默認的命名空間,具體如下:
<book xmlns="http://www.atguigu.com/xml/b"
xmlns:a="http://www.atguigu.com/xml/a">
上邊的 xmlns="http://www.atguigu.com/xml/b" 並沒有指定前綴,那么這種沒有指定前綴的命名空間就會作為頁面中元素的默認命名空間,除非在標簽中使用其他命名空間的前綴,否則解析器都會認為元素是在默認命名空間下存在。
但是要注意的是一個文檔中只能有一個默認的命名空間,如下的語法是錯誤的:
<book xmlns="http://www.atguigu.com/xml/b"
xmlns="http://www.atguigu.com/xml/a">
這里我們指定了兩個命名空間而都沒有使用前綴,解析器在解析文檔時會不知道使用哪個命名空間,所以在一個文檔中只能有一個默認的命名空間,其他命名空間必須使用前綴。
六、舉例
我們這里就以 Spring 中的 XML 文件來進行說明
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.springmvc"></context:component-scan>
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
<?xml version="1.0" encoding="UTF-8"?> : XML 格式頭文件
xmlns="http://www.springframework.org/schema/beans" : 這里沒有帶有前綴,是默認的命名空間,這個空間是屬於那些沒有寫任何前綴的標簽,例如 bean 標簽就沒有寫任何前綴,bean 標簽就屬於這個命名空間
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" : xsi 是 XML Schema Instance 的縮寫,也可以自己起別的前綴名(不推薦自己亂起名字,使用約定俗成的前綴可以使xml文件結構更加清晰)。
這是一個特殊的命名空間,它已經定義好了4個標簽分別是 xsi:type、xsi:nil、xsi:schemaLocation、xsi:noNamespaceSchemaLocation ,這幾個屬性只有聲明了 xsi 命名空間后才能使用,這里我們只講我們用到的 xsi:schemaLocation 這個屬性
xsi:schemaLocation:這個標簽的值分為兩個部分,對應的是兩個 uri 地址,使用空格將它們分開,空格前是 xsd 文件的目標命名空間,空格后是 xsd 文件的所在物理位置,它的的作用是引用 xsd 文件來校驗指定命名的格式.例如:
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
它代表的意思是 引用外部的 http://www.springframework.org/schema/beans/spring-beans.xsd 約束文件來對 http://www.springframework.org/schema/beans 這個名稱空間里的元素進行對應的語法、規范約束.
<context:component-scan base-package="com.springmvc"></context:component-scan> :
對應的名稱空間是 xmlns:context="http://www.springframework.org/schema/context" ,主要是起到一個唯一標識的作用.