DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> xml-了解 XML 命名空間 - asp.net
xml-了解 XML 命名空間 - asp.net
編輯:XML詳解     
r> 什麼是命名空間?
編程語言中的命名空間
XML 中的命名空間
對命名空間進行命名
定義命名空間
使用命名空間
命名空間抽象
小結

由 Aaron Skonnard 撰寫的“了解 XML 命名空間”最初刊登在 2001 年 7 月的 MSDN Magazine 中。此更新版本的使用經過授權。版權所有 ? 2001 Microsoft Corp. 和 CMP Media LLC。

命名空間是 XML 中許多混淆的來源,初學該技術的用戶對命名空間尤其感到困惑。讀者、學生和與會者經常問到的問題總是與命名空間有關。這實際上具有一定的諷刺意味,因為 Namespaces in XML Recommendation 是一種精簡的 XML 規范(不含附錄,不超過 10 頁)。然而,這種混淆與命名空間語義有關,而與該規范中概述的語法無關。為了充分了解 XML 命名空間,您必須知道什麼是命名空間、如何定義命名空間以及如何使用它們。

本專欄的其余部分將專門從語法和理論上回答這三個問題。在讀完本文後,您將了解命名空間是如何影響 XML 技術家族的。

什麼是命名空間?
命名空間是一組保持唯一的名稱。例如,可以將我所有孩子的姓名視為一個命名空間,就像加利福尼亞州的公司的名稱、C++ 類型標識符的名稱或 Internet 域名。命名空間就是在邏輯上相關的任何一組名稱,而且每個名稱都必須唯一。

使用命名空間更便於產生唯一的名稱。設想一下,如果姓名必須在全球保持唯一,那麼,要給自己的下一個小孩起名將會多麼困難。如果將唯一性限制在一個更窄的上下文(例如,我的所有孩子)中,情況就會簡單得多。當我為我的下一個孩子起名時,我只需考慮不使用與我的其他孩子重名的名字。另一組父母可以為他們的某個孩子選擇我已使用過的姓名,但是這些姓名必須屬於不同的命名空間,以便易於區分。

在將新名稱添加到某個命名空間中之前,命名空間機構必須確保該命名空間中沒有這個新名稱。在某些情況下,這會非常簡單,因為它屬於子命名系統。在其他情況下,這會相當復雜。當今的許多 Internet 命名機構就是一個現實的例子。然而,如果忽略此步驟,重復的名稱最終會損壞該命名空間,這使得無法引用某些沒有多義性的名稱。如果出現這種情況,這組名稱將不再被正式視為命名空間 — 根據定義,命名空間必須確保它的成員具有唯一性。

為了使命名空間有用,還必須為其本身賦予名稱。在命名空間有了名稱之後,就可以引用其成員。例如,考慮顯示在圖 1 兩個框中的示例命名空間,這兩個示例命名空間的名稱分別是 Microsoft 和 AcmeHardware。請注意,即使這兩個命名空間都包含一些相同的本地名稱,也可以通過由命名空間限定的名稱來引用沒有多義性的本地名稱,如圖1 所示。



圖 1. 非多義性命名空間

當然,其前提是假設這些命名空間名稱也是唯一的。如果不能保證這一點,則還可以將實際命名空間名稱本身放到其各自的命名空間中。例如,如果有多個 AcmeHardware 商店(一個在加利福尼亞州,一個在猶他州),則將名稱 AcmeHardware 放在兩個不同的命名空間就會解決這種沖突,如下所示:

California.AcmeHardware.Paint
Utah.AcmeHardware.Paint

這種模式可根據需要重復任意多次,以保證命名空間名稱的唯一性。這與 Internet 域名系統 (DNS) 的工作方式完全相同,DNS 就是一個由多個命名空間組成的大命名空間。

如果沒有這種類型的命名空間分區,您將不得不使用極長(不常用)的名稱來確保唯一性:

MicrosoftWindowsOperatingSystemPaintApplication

設想一下,如果只有一個不能進行分區的全局命名空間,會有多麼復雜、多麼令人頭痛。人們在日常社交中相當依賴命名空間,盡管在大多數情況下人們並沒有清楚地意識到這一點。然而,要在軟件開發中使用命名空間,必須通過具體的語法明確它們。在轉入討論 XML 中的命名空間之前,讓我們看一下當今某個主流編程語言中命名空間的語法示例。

返回頁首
編程語言中的命名空間
要在某個編程語言中使用命名空間,您必須熟悉用來定義命名空間並引用其中的某些內容的語法。當今的許多語言(包括 C++、Java 和 C#)為命名空間提供支持。在 C++ 中,命名空間是通過命名空間塊來定義的,如下所示。

namespace foo1
{
class bar
{
????????????
};
class baz
{
????????????
};
}
namespace foo2
{
class bar
{
????????????
};
class baz
{
????????????
};
}

本例定義了兩個命名空間:foo1 和 foo2。這兩個命名空間均包含兩個名稱:bar 和 baz(在本例中,它們是類標識符)。

foo1::bar b1; // refers to bar class in foo1
foo2::bar b2; // refers to bar class in foo2

要引用特定命名空間的 bar 類,必須用給定的命名空間標識符來限定 bar 標識符。

為方便起見,還可以做如下聲明:在給定的源文件中使用特定的命名空間。這會從本質上使指定的命名空間成為源文件的默認命名空間。於是,就沒有必要完全限定特定的命名空間成員,當然,在絕對有必要避免多義性時也可以完全限定:

using namespace foo1;
bar b1; // refers to bar class in foo1

正如您所看到的,C++ 中定義和使用命名空間的語法簡單明了。C# 的工作方式與 C++ 非常相似,只是有幾個小區別。Java 中的命名空間語法稍有不同,但概念是相同的。

在許多編程語言中,命名空間可用來幫助避免名稱沖突,這正是完成 XML 1.0 規范所需的解決方案類型。

返回頁首
XML 中的命名空間
因為 XML 1.0 規范不提供命名空間支持,所以許多開發人員感到它不完整。因此,用在 XML 文檔中的所有名稱都屬於一個全局命名空間,這便難於實現唯一的名稱。

許多開發人員(包括 XML 1.0 作者本身)知道這在基於 XML 的大型分布式系統中最終會導致太多的多義性。例如,考慮下面的 XML 文檔:

<student>
<id>3235329</id>
<name>Jeff Smith</name>
<language>C#</language>
<rating>9.5</rating>
</student>

此文檔使用幾個名稱,每個名稱都相當普通。student 元素對軟件培訓課程的學生進行建模。id、language 和 rating 元素對學生的數據庫記錄編號、首選的編程語言以及學生對該課程的評分(基准分是 10)進行建模。其中的每個名稱肯定都會在其他情況下用到 — 在這些情況下,它們會具有不同的含義。

例如,下面是另一個 XML 文檔,它以一種完全不同的方式來使用相同的名稱:

<student>
<id>534-22-5252</id>
<name>Jill Smith</name>
<language>Spanish</language>
<rating>3.2</rating>
</student>

在本例中,student 元素對小學生進行建模。現在,id、language 和 rating 元素分別對孩子的社會保障號、本民族語言和當前的年級平均成績(基准分是 4)進行建模。這兩個文檔的作者可以使用較長的、不太常用的名稱來幫助確保實現唯一性,但這最終還是無法保證唯一性,而且更加難以使用。

盡管人們能夠在查看這兩個文檔後找出二者的區別,但是它們對於軟件來說看上去卻完全相同。設想一下,您負責構建一個學生管理應用程序,該應用程序必須支持與學生有關的許多不同的 XML 文檔(包括剛提到的兩個文檔)。在編寫代碼時,您打算如何(從編程上)區分專業學生和小學生或者任何其他類型的學生?沒有一種可靠的方法來進行這種區分。

在同一個文檔或應用程序中使用來自不同 XML 詞匯表中的元素和屬性,無論如何都會產生命名沖突。請考慮 XSLT,它本身是用來定義轉換的 XML 詞匯表。在給定的轉換中,可以輸出用戶定義的文本元素。因此,既然 XSLT 詞匯表中包含名為 template 的元素,那麼如何輸出名稱同樣為 template 的用戶定義的文本元素呢?

<!-- this is the template element from XSLT -->
<template match="foo">
<!-- I want to output this template element -->
<template match="foo"/>
</template>

在大量混合 XML 詞匯表的語言(例如,XSLT 和 XML 架構)中,出現名稱沖突的可能性極大。然而,如果 XML 提供對命名空間的支持,就可以很容易地避免這些問題的發生。

“Namespaces in XML Recommendation” 是 W3C 為 XML 1.0 命名問題提供的解決方案。此規范定義了如何對 XML 1.0 具體語法進行擴展,以便支持命名空間。因為大多數開發人員都認為這個新增功能是絕對有必要添加的基本功能,所以此規范通常被視為 XML 1.0 的正式補充,盡管它不是正式的。實際上,許多開發人員現在拒絕單獨提及 XML 1.0,而是提及“XML 1.0 + 命名空間”,其原因就在於此。

“Namespaces in XML Recommendation” 定義了 XML 命名空間的命名語法以及在 XML 命名空間中引用某些內容的語法。然而,它沒有涉及到用來定義 XML 命名空間中有何內容的語法。這留給了另一個規范(即,XML 架構)。其中的每個領域都需要一些解釋。

返回頁首
對命名空間進行命名
當您在編程語言(例如,C++)中定義命名空間時,有一些對可用在該名稱中的字符的限制。XML 命名空間標識符還必須符合特定的語法 — 統一資源標識符 (URI) 引用的語法。這表示 XML 命名空間標識符必須遵守由 RFC 2396 定義的 URI 的常用語法。

URI 被定義為用來標識抽象或物理資源的緊湊字符串。在大多數情況下,URI 引用用來標識物理資源(網頁、要下載的文件等),但是,對於 XML 命名空間來說,URI 引用用於標識抽象資源(特別是命名空間)。

按照 URI 規范,有兩種常規類型的 URI:統一資源****************** (URL) 和統一資源名稱 (URN)。這兩種類型的 URI 都可以用作命名空間標識符。下面是一個可用作命名空間標識符的兩個 URL 的示例:

http://www.develop.com/student
http://www.ed.gov/elementary/students

下面是幾個也可用作命名空間標識符的 URN 的示例:

urn:www-develop-com:student
urn:www.ed.gov:elementary.students
urn:uuid:E7F73B13-05FE-44ec-81CE-F898C4A6CDB4

命名空間標識符最重要的屬性是它的唯一性。作者可以通過向 Internet 命名機構注冊域名來保證 URL 的唯一性,然後要負責確保域名後面使用的所有字符串都保持唯一。

URN 以同樣的方式工作。下面是基本的 URN 語法:

urn:<namespace identifIEr>:<namespace specific string>

為了保證 URN 的一致性,作者必須再次向 Internet 命名機構注冊他們的命名空間標識符。然後,作者負責按照某個方案來生成特定於命名空間的唯一字符串。

定義 XML 命名空間的組織應當為新命名空間名稱的創建制定一個一致的方案。例如,W3C 經常定義新的 XML 命名空間。這些組織使用一個相當直觀的試探法,該試探法使用當前年份以及工作組的名稱。圖 2 闡釋了由 W3C 使用的模式。



圖 2. W3C URI 構造

根據定義,URI 是唯一的,因此完全不必在 XML 命名空間標識符的上面放置其他命名空間。只要命名空間作者保證命名空間標識符的唯一性,總是可以只用單個命名空間限定符來唯一地標識 XML 中的內容。這大大簡化了這一在 XML 中處理命名空間的工作。

XML 處理器將命名空間標識符視為不透明的字符串,而從不將它們視為可解析的資源。重申一遍:命名空間標識符僅僅是字符串!當兩個命名空間標識符中的各個字符都完全相同時,它們就被視為相同。

最後,它確實與選擇使用哪個類型的 URI 引用無關。許多開發人員因 URL 更易於讀取和記憶而喜歡使用它們,而其他開發人員因 URN 的靈活性而喜歡使用它們。無論選擇哪種類型,您都要確保知道如何保證唯一性。

返回頁首
定義命名空間
“Namespaces in XML Recommendation” 沒有提供用來定義 XML 命名空間中有何內容的語法。在許多情況下,這種類型的語法定義甚至不是必需的。目前,大多數 XML 命名空間都是在正式規范文檔中定義的,這些文檔描述元素的名稱,以及屬性及其語義。這恰好說明了如何正式定義所有的 W3C 命名空間(請參閱 http://www.w3.org/TR/xslt 上的 XSLT 1.0 規范,以查看相關示例)。

在定義了某個命名空間之後,軟件開發人員按照規范中所概述的那樣實現該命名空間。例如,MSXML 3.0、Xalan 和 Saxon 都是對 XSLT 1.0 規范的實現。對這些實現進行硬編碼,以便查找那些屬於 XSLT 1.0 命名空間 (http://www.w3.org/1999/XSL/Transform) 的元素。要使用這些實現,您需要向它們提供一個正確使用 XSLT 1.0 命名空間中名稱的 XML 文檔(下一節將介紹這方面的詳細信息)。如果要更改 XSLT 1.0 命名空間中的任何內容,支持軟件將必須進行更新。

XML 架構工作組 (http://www.w3.org/XML/Schema) 已經合並了一個新規范(XML 架構),該規范為在命名空間中定義元素、屬性和類型定義了一個基於 XML 的語法。XML 架構最終使得提供命名空間的語法定義成為可能,如下所示。

<schema xmlns=@#http://www.w3.org/2000/10/XMLSchema@#
targetNamespace=@#http://www.develop.com/student@#
elementFormDefault=@#qualifIEd@#
>
<element name=@#student@#>
<complexType>
<sequence>
<element name=@#id@# type=@#long@#/>
<element name=@#name@# type=@#string@#/>
<element name=@#language@# type=@#string@#/>
<element name=@#rating@# type=@#double@#/>
</sequence>
</complexType>
</element>
</schema>

本例定義的 http://www.develop.com/student 命名空間包含五個命名元素:student、id、name、language 和 rating。此架構不僅提供命名空間,而且還提供其他元數據,例如,student 子元素的順序以及它們的類型。

在有了語法命名空間定義(例如,那些由 XML 架構提供的定義)時,就可以構建更高級的軟件,以便在運行時利用名稱和類型信息。XML 架構仍然未定義所定義元素和屬性的語義,因此仍將需要一個隨附的規范。將來,大多數 XML 命名空間都將通過規范和架構定義同時定義。

返回頁首
使用命名空間
我將命名空間的使用過程定義為:使用 XML 文檔中給定命名空間中的一個或多個元素或屬性。這要求您了解如下由 “Namespaces in XML Recommendation” 概述的語法:用命名空間標識符限定元素名稱和屬性名稱。

元素和屬性的名稱實際上都由兩部分組成:一個命名空間名稱和一個本地名稱。這樣的兩部分名稱就是所謂的限定名或 QName。

在 XML 文檔中,我們使用命名空間前綴來限定元素和屬性的本地名稱。前綴實際上只是命名空間標識符 (URI) 的縮寫,URI 通常相當長。前綴首先通過命名空間聲明映射到命名空間標識符。命名空間聲明的語法是:

XMLns:<prefix>=@#<namespace identifIEr>@#

命名空間聲明看起來就像(元素的)屬性,但是從文檔的邏輯結構來看,它們不被正式視為屬性(即,在使用 DOM 時,它們將不出現在元素的屬性集中)。

命名空間前綴被視為在聲明元素以及它的任何子代元素的作用域內。聲明的前綴可用在任何元素或屬性名稱的前面(用冒號分隔,例如,s:student)。這個包括前綴的完整名稱是限定名 (QName) 的詞法形式:

QName = <prefix>:<local name>

前綴通過映射到當前位於作用域中的前綴的命名空間標識符與元素或屬性關聯。

讓我們假設某個開發人員希望使用 XSLT 1.0 命名空間。他將需要提供一個命名空間聲明,以便將任意前綴映射到正式的 XSLT 1.0 命名空間標識符 (http://www.w3.org/1999/XSL/Transform)。然後,只需在該開發人員希望從 XSLT 1.0 命名空間中使用的每個元素或屬性前面加上相應的前綴,如下例所示:

<x:transform version=@#1.0@#
XMLns:x=@#http://www.w3.org/1999/XSL/Transform@#
>
<x:template match=@#/@#>
<hello_world/>
</x:template>
</x:transform>

上例顯示了在命名空間中引用元素的語法。前綴為 “x” 的每個元素都來自 http://www.w3.org/1999/XSL/Transform 命名空間,而沒有前綴的任何元素(例如,hello_world)都不來自命名空間。處理器現在可以區分 XSLT 1.0 編程構造和將要輸出的文本元素(例如,hello_world)。如果 XSLT 1.0 命名空間中有一個字符拼錯了,則 XSLT 1.0 處理器將無法將該文檔識別為它能夠理解的詞匯。

在本質上,每個元素現在都有一個由兩部分組成的名稱:一個命名空間標識符和一個本地名稱。這兩個名稱組合在一起通常稱作命名空間名稱(注意:這不同於 QName,QName 由前綴和本地名稱組合而成)。

下面的 XML 文檔是另一個示例,它顯示了如何從本專欄前面顯示的 XML 架構定義使用元素:

<d:student XMLns:d=@#http://www.develop.com/student@#>
<d:id>3235329</d:id>
<d:name>Jeff Smith</d:name>
<d:language>C#</d:language>
<d:rating>9.5</d:rating>
</d:student>

請注意,無論命名空間是如何定義的,引用它們的語法都是相同的。

當文檔使用多個命名空間中的元素或屬性時,通常針對給定的元素進行多個命名空間聲明,如下例所示:

<d:student XMLns:d=@#http://www.develop.com/student@#
XMLns:i=@#urn:schemas-develop-com:identifIErs@#
XMLns:p=@#urn:schemas-develop-com:programming-languages@#
>
<i:id>3235329</i:id>
<name>Jeff Smith</name>
<p:language>C#</p:language>
<d:rating>9.5</d:rating>
</d:student>

在這裡,student 和 rating 來自同一個命名空間,而 id 和 language 分別來自不同的命名空間,但是 name 不屬於命名空間。

命名空間前綴還可以通過在嵌套作用域中重新聲明來進行重寫,如下所示:

<d:student XMLns:d=@#http://www.develop.com/student@#>
<d:id>3235329</d:id>
<d:name XMLns:d=@#urn:names-r-us@#>Jeff Smith</d:name>
<d:language>C#</d:language>
<d:rating>35</d:rating>
</d:student>

在本例中,除了 name 元素,所有的內容都來自同一個命名空間 — urn:names-r-us 命名空間。盡管可以重新聲明命名空間前綴,但是卻無法取消對命名空間前綴的聲明。例如,下面的聲明是非法的:

<d:student XMLns:d=@#http://www.develop.com/student@#>
<d:id XMLns:d=@#@#>3235329</d:id>
?·?·?·
</d:student>

對於大多數軟件開發人員來說,面向前綴的語法(用來在 XML 命名空間中引用內容)是相當直觀的。如果 “Namespaces in XML Recommendation” 只包含這些內容,則命名空間所引起的混淆會小得多。

默認命名空間

可以使用另一種類型的命名空間聲明來將命名空間標識符與元素名稱相關聯。這就是所謂的默認命名空間聲明,它使用下面的語法:

XMLns=@#<namespace identifIEr>@#

請注意,這裡沒有前綴。在針對某個元素使用默認命名空間聲明時,其作用域中的所有非限定元素名稱都自動與指定的命名空間標識符相關聯。然而,默認命名空間聲明決不會影響屬性。如果要將屬性與命名空間標識符相關聯,唯一的方法就是使用前綴。

請考慮下例:

<d:student XMLns:d=@#http://www.develop.com/student@#
XMLns=@#urn:foo@# id=@#3235329@#
>
<name>Jeff Smith</name>
<language XMLns=@#@#>C#</language>
<rating>35</rating>
</d:student>

在這裡,“student” 來自 http://www.develop.com/student 命名空間,而 “name” 和 “rating” 來自默認命名空間 urn:foo。id 屬性不屬於命名空間,這是由於屬性不會自動與默認的命名空間標識符相關聯。

本例還闡釋了您可以取消對默認命名空間的聲明(只需將默認的命名空間標識符重新設置為空字符串),如 language 元素所示(請記住,對於前綴聲明不能這樣做)。因此,language 元素也不屬於命名空間。

默認命名空間的語法旨在提高方便程度,但是它們會導致更多的混淆,而不是帶來更大的價值。這種混淆通常源自如下事實:元素和屬性以不同的方式處理,而且嵌套元素被指定為默認的命名空間標識符也不是立即可見的。然而,除了屬性起作用時,在前綴和默認命名空間之間進行選擇最終將主要是樣式方面的問題。


返回頁首
命名空間抽象
從 XML 文檔的抽象視圖處理命名空間比處理剛描述的詞法問題簡單得多。XML 信息集 (Infoset) 定義 XML 文檔的抽象結構,這使開發人員不再處理復雜的基礎序列化格式(例如,剛描述的命名空間語法)。

按照 Infoset,每個元素或屬性都有兩個名稱屬性:一個命名空間標識符和一個本地名稱。圖 3 闡釋了一個 XML 文檔的邏輯結構,該文檔中包含命名空間限定的名稱。請注意,student、id 和 language 都來自同一個命名空間,而 rating 來自另一個命名空間,name 不屬於命名空間。此文檔可通過上一節中描述的任一方法進行序列化。



圖 3. 命名空間限定的 XML 文檔

請考慮當今的主流 API、SAX 和 DOM 如何實現這個抽象數據模型。SAX 通過 ContentHandler 的 startElement/endElement 方法調用來對元素進行建模:

public interface contentHandler
{
????????????
void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException;
void endElement(String namespaceURI, String localName,
String qName) throws SAXException;
????????????
}

請注意,這些元素由它們的命名空間標識符和本地名稱(可以選擇使用 QName)的組合來標識。屬性還可以通過一組能夠針對 Attributes 接口識別命名空間的方法來標識。SAX 分析器(或者任何其他制作者的應用程序)負責提供命名空間名稱,因為它提供文檔流。也就是說,在使用 SAX 時,以編程方式區分不同類型的 student 元素將會非常簡單。

????????????
void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
{
if ( namespaceURI.equals("urn:dm:student") &&
localName.equals("student") )
{
// process Developmentor student element here
}
else if ( namespaceURI.equals("urn:www.ed.gov:student")
&& localName.equals("student") )
{
// process elementary school student element here
}
}
????????????

由於命名空間名稱(命名空間標識符 + 本地名稱)是由 SAX 分析器自動解析的,因此,在源文檔中的特定元素或屬性中使用什麼前綴(如果有的話)並不重要 — 它主要是序列化細節。然而,這並不表示前綴在經過分析之後就可以被扔掉。考慮下面的 XML 文檔:

<student xmlns:xsd=@#http://www.w3.org/2000/10/XMLSchema@#
xmlns:xsi=@#http://www.w3.org/2000/10/XMLSchema-instance@#
>
<age xsi:type=@#xsd:double@#>35.0</age>
</student>

請注意,在該 XML 架構中,age 的 xsi:type 屬性包含一個 QName 值。無論何時在元素或屬性內容中使用 QName,商業應用程序都必須手動處理它。只有知道了 “xsd” 要綁定到哪個命名空間標識符,商業應用程序才能正確地解釋此值。因此,Infoset 對於文檔中的每個元素還維護一組作用域內的命名空間聲明。SAX 通過 startPrefixMapping 和 endPrefixMapping 方法調用對該信息進行建模。

DOM API 是對 Infoset 的另一個實現。DOM 的 Node 接口通過以下兩個名稱屬性對元素/屬性節點的基本標識進行建模:namespaceURI 和 localName。它還通過 nodeName 和 prefix 屬性對節點的 QName 和前綴進行建模。下面的 Java 語言代碼闡釋了如何使用 DOM 來區分兩個不同的 student 元素。

void processStudent(Node n)
{
if ( n.getNamespaceURI().equals("urn:dm:student") &&
n.getLocalName().equals("student") )
{
// process Developmentor student element here
}
else if (
n.getNamespaceURI().equals("urn:www.ed.gov:student")
&& n.getLocalName().equals("student") )
{
// process elementary school student element here
}
}

正如對於 SAX 一樣,用來構建 DOM 樹的 XML 分析器負責填充相應的命名空間屬性。因此,在使用邏輯文檔結構時,如何在源文檔中聲明命名空間同樣並不重要。如果您要通過 DOM API 創建文檔,則您需要負責在創建文檔時為每個元素和屬性提供命名空間標識符:

void generateStudentDocument(Document doc)
{
Node docEl = doc.createElementNS("urn:dm:student", "student");
doc.appendChild(docEl);
Node n = doc.createElementNS("", "name");
docEl.appendChild(n);
????????????

正如您所看到的那樣,此代碼允許您直接創建邏輯結構。然後,由 DOM 實現來負責確定如何將命名空間聲明序列化為基礎 XML 1.0 文檔。這個 DOM 樹可按如下方式進行序列化:

<student XMLns=@#urn:dm:student@#>
<name XMLns=@#@#/>
</student>

當您(通過 SAX/DOM API)處理 XML 文檔的抽象視圖時,一定要注意其中沒有默認命名空間的概念。在前面提到的示例中,在針對 “student” 調用 createElementNS 之後,urn:dm:student 不會神奇地變成默認命名空間。如果針對沒有命名空間的 “name” 調用 createElementNS,就會向 name 元素賦予空的命名空間標識符(不是 urn:dm:student)。就一系列 startElement/endElement 方法調用而言,這同樣適用於 SAX。每個元素/屬性節點總是以獨立於名稱信息的方式進行處理。

XPath 是另一個 XML 規范,它定義如何在抽象文檔結構中標識節點。XPath 表達式允許通過命名空間限定的名稱來標識元素和屬性。由於 XPath 名稱測試是簡單的字符串表達式,所以只能通過命名空間前綴來將 XPath 名稱測試與命名空間標識符相關聯。

您可以將 XPath 節點測試視為屬於 QName 類型。這就是說,如果某個節點測試不包括前綴,就像是要查找不屬於命名空間的給定名稱。例如,請使用下面的 XPath 表達式:

/student/name

此表達式標識不屬於命名空間的、作為不屬於命名空間的根 student 元素的子級的所有 name 元素。要標識屬於 urn:dm:student 命名空間的 student 和 name 元素,首先必須將命名空間前綴與 urn:dm:student 相關聯。然後就可以在 XPath 表達式中使用該前綴了。

假設 “dm” 已經與 XPath 上下文中的 urn:dm:student 相關聯,則下面的表達式現在將標識屬於 urn:dm:store 命名空間的、作為同樣屬於 urn:dm:store 命名空間的根 student 元素的子級的 name 元素:

/dm:student/dm:name

如果查詢到的文檔看上去像下面的代碼,則上面的表達式將標識作為 student 子級的所有三個 name 元素(與它們的前綴無關),這是由於它們都來自所討論的同一個命名空間。

<s:student XMLns:s=@#urn:dm:student@#>
<s:name/>
<n:name XMLns:n=@#urn:dm:student@#/>
<s:name/>
</s:student>

在 XPath 上下文中,前綴以與實現相關的方式進行映射(有關如何在 MSXML 3.0 中進行此操作的詳細信息,請參閱 2001 年 5 月的 The XML Files 專欄)。XSLT 就是這樣的一個示例,它提供了一個使用 XPath 表達式的上下文。要在 XSLT 文檔中使用命名空間限定的 XPath 表達式,可以使用標准的命名空間聲明來將目標命名空間標識符映射到任意前綴:

<x:transform version=@#1.0@#
XMLns:x=@#http://www.w3.org/1999/XSL/Transform@#
XMLns:d=@#urn:dm:student@#
>
<x:template match=@#d:student@#>
<!-- transform student here -->
<x:apply-templates select=@#d:name@#/>
</x:template>
?·?·?·
</x:transform>

請注意,第一個模板針對 urn:dm:student 命名空間中的 student 元素進行匹配。如果匹配值只是 “student”,它將只匹配不屬於命名空間的 student 元素。apply-templates 元素隨後處理所有的 name 子元素,這些子元素也屬於 urn:dm:student 命名空間。

正如您所看到的那樣,從詞法和理論上了解命名空間的工作方式,對於了解 XML 規范的整個系列來說是至關重要的。隨著 XML 規范的不斷湧現,您將遇到許多與所發生的情況相類似的情況。


返回頁首
小結
命名空間是一組保持唯一的名稱。XML 中的命名空間允許為元素和屬性提供唯一的名稱。盡管命名空間總是成為許多混淆的來源,但是在從語法和理論上熟悉了它們的定義和使用方式之後,您會很容易理解它們。有關命名空間的更多信息,請參閱 Namespaces in XML Recommendation 和 XML Namespaces by Example。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved