- XML实用技术自学经典
- 伍逸编著
- 4178字
- 2025-02-17 20:31:37
2.2 声明命名空间
在声明命名空间时,如果不遵从一定的命名规则,难免会产生重名的命名空间。为了尽量避免发生这种问题,W3C组织推荐用户使用两种方式:URIs或URNs去产生唯一的命名空间。当然这并不意味着用户不能采用其他的方式去声明命名空间,但本书仍建议遵从W3C组织推荐的方式。
2.2.1 URL、URI和URN
在选择用什么方式声明命名空间前,有必要澄清URL、URI和URN的概念。
1.URL
URL是Uniform Resource Location(统一资源定位符)的缩写。通俗地说,URL是因特网上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上。采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
URL的格式如下。
[Scheme]://[Domain]:[Port]/[Path]?[QueryString]#[FragmentId]
URL的格式由下列3部分组成:
第1部分是协议(或称为服务方式);
第2部分是存有该资源的主机IP地址(有时也包括端口号);
第3部分是主机资源的具体地址,如目录和文件名等。
第1部分和第2部分之间用“://”符号隔开,第2部分和第3部分用“/”符号隔开。第1部分和第2部分是不可缺少的,第3部分有时可以省略。
例如http://www.cnd.org/pub/HXWZ就是一个典型的URL地址。
客户程序首先看到http(超文本传送协议),便知道处理的是HTML链接。接下来的www.cnd.org是站点地址,最后是目录pub/HXWZ。
对于URL地址ftp://ftp.cnd.org/pub/HXWZ/cm9612a.GB,WWW客户程序需要用FTP去进行文件传送,站点是ftp.cnd.org,然后去目录pub/HXWZ下,下载文件cm9612a.GB。
如果上面的URL是ftp://ftp.cnd.org:8001/pub/HXWZ/cm9612a.GB,则FTP客户程序将从站点ftp.cnd.org的8001端口连入。
必须注意,WWW上的服务器都是区分大小写字母的,所以,千万要注意应使用正确的URL大小写表达形式。
2.URI
URI是Uniform Resource Identifier(通用资源标志符)的缩写。它是因特网的一个协议要素,可以通过它来定位任何远程或本地的可用资源(这些资源通常包括HTML文档、图像、视频片段、程序等)。
URI一般由3部分组成:
·访问资源的命名机制;
·存放资源的主机名;
·资源自身的名称,由路径表示。
考虑下面的URI,它表示了当前的HTML 4.0规范。
http://soft.yesky.com/lesson/148/2623648.shtml
这个URI意味着:这是一个可通过HTTP协议访问的资源,位于主机soft.yesky.com上,通过路径/lesson/148/来访问。在HTML文档中其他资源,包括mailto和ftp也是URI。
以下是URI的另一个例子,指向一个用户的邮箱。
<A href=mailto:luokl@chinabyte.com>邮件
有的URI指向一个资源的内部。这种URI以“#”结束,并跟着一个anchor标志符(称为片段标志符)。例如,下面的例子是一个指向section_2的URI。
http://somesite.com/html/top.htm#section_2
相对URI不包含任何命名规范信息。它的路径通常指同一台机器上的资源。相对URI可能含有相对路径(如,“..”表示上一层路径),还可能包含片段标志符。
为了说明相对URI,假设有一个基本的URI,http://homepage.yesky.com/。
下面的链接中使用了相对URI。
<A href="104/2627604.shtml">网页</A>
将它扩展成完全的URI就是http://homepage.yesky.com/104/2627604.shtml。
下面是一个图像的相对URI。
<IMG src="../TLimages/img/head/logo.gif" alt="logo">
它扩展成完全的URI就是http://homepage.yesky.com/TLimages/img/head/logo.gif。
在HTML中,URI被用于如下场合。
·链接到另一个文档或资源(<A>和<LINK>元素)。
·链接到一个外部样式表或脚本(<LINK>和<SCRIPT>元素)。
·在网页内包含的图像、对象或applet(<IMAG>、<OBJECT>、<APPLET>和<INPUT>元素)。
·建立图像映射(<MAP>和<AREA>元素)。
·提交一个表单(<FORM>元素)。
·建立一个框架文档(<FRAME>和<IFRAME>元素)。
·引用一个外部参考(<Q>、<BLOCKQUOTE>、<INS>和<DEL>元素)。
·指向一个描述文档的metadata(<HEAD>元素)。
URI包括两个子集:URL和URN。大多数读者可能熟悉URL,而不是URI。URL是URI命名机制的一个子集。
3.URN
URN是Uniform Resource Name(统一资源名称)的缩写,它是URL的一种更新形式。URN是作为特定内容的唯一名称使用的,与目前的资源所在地无关。使用这些与位置无关的URN,就可以将资源四处搬移。通过URN,还能以同一个名字通过多种网络访问协议来访问资源。URN的格式如下。
urn:[namespace identifier]:[namespace specific string]
举例来说,不论因特网标准文档RFC 2141位于何处(甚至可以将其复制到多个地方),都可以用下面的URN来命名它。
urn:ietf:rfc:2141
目前,URN仍处于试验阶段,还未大范围使用。为了更有效地工作,URN需要一个支撑架构来解析资源的位置,而此类架构的缺乏延缓了其被采用的进度,但URN却为未来发展做出了一些令人兴奋的承诺。
简而言之,URL和URN都是URI的子集,URL告诉用户资源的地点及访问方式,而URN就是一个唯一的资源名称。URL和URN都可用于创建XML命名空间的URI。
2.2.2 创建命名空间
如前所述,当创建命名空间时,应该使用URI格式,且该URI必须是唯一的,以避免与别人选择的命名空间发生冲突。由于大多数企业和独立软件开发商有自己的注册域名,因而用自己的域名作为XML文档命名空间的起点已经成为业界的推荐标准。其后的部分用户可以用自己最想要的字符任意组合,但应避免应用空格和问号。假设注册域名为http://wrm.com/,现在需要在人事部门关于员工的那个XML文档中使用命名空间,就可以选择如下完整的命名空间。http://wrm.com/namespace/hr/employee。
命名空间是区分大小写的,所以尽量用全小写字母。
1.声明命名空间
命名空间被声明为元素的属性。并不一定只在根元素中声明命名空间,而是可以在XML文档的任何元素中进行声明。用户可以通过两种方式声明命名空间,这取决于是否要将文档中的所有元素都包含在命名空间中或只将少数几个特定的元素包含在命名空间中。如果想包含所有元素,可以使用以下方式(这种方式被称为声明默认命名空间)。
xmlns= “http://wrm.com/namespace/hr/employee”
假设公司人事部具有如下的关于员工的XML文档。
employees.xml
<?xml version="1.0" encode="UTF-8" ?>
<hrEmployees>
<employee firstName="Joe" lastName="Fawcett" />
<employee firstName="Danny" lastName="Ayers" />
<employee firstName="Catherine" lastName="Middleton" />
</hrEmployees>
添加命名空间声明,则上面的文档(employees.xml)变为如下形式。
<?xml version="1.0" encode="UTF-8" ?> <hrEmployees xmlns= "http://wrm.com/namespace/hr/employee"> <employee firstName="Joe" lastName="Fawcett" /> <employee firstName="Danny" lastName="Ayers" /> <employee firstName="Catherine" lastName="Middleton" /> </hrEmployees>
这就为XML文档声明了一个默认命名空间。在这种情况下,根元素<hrEmployees>及其包含的所有元素都与默认命名空间相关联。必须要注意,元素的属性,如firstName,不属于该默认命名空间。默认命名空间声明可以通过将xmlns属性的值设置为空字符串来取消声明。应当避免取消对默认命名空间声明的声明,因为这一做法可能导致在文档的一部分具有属于某个命名空间且不带前缀的名称,但是在另一部分却没有。例如,在下面的文档中:
<bookstore xmlns="http://25hoursaday-com/bookstore"> <book xmlns=""> <title>Lord of the Rings</title> <author>J.R.R. Tolkien</author> </book> </bookstore>
只有<bookstore>元素来自http://25hoursaday-com/bookstore,而其他不带前缀的元素则没有命名空间名称。
默认命名空间只适用于元素。属性也可以添加命名空间,用于进行具体地声明。在XML文档的其他部件,如注释,没有相关联的命名空间。假设现在需要为employees.xml中的属性,如firstName,添加相关联的命名空间,如http://wrm.com/namespace/hr/employee,格式如下。
{http://wrm.com/namespace/hr/employee}firstName
以这种格式来添加XML文档的属性或元素的命名空间,显得十分烦琐,且容易造成文档的杂乱不堪,因而可以采用另外一种声明命名空间的方式,即将命名空间URI映射到特定的前缀,格式如下。
<someElement xmlns:prefix="namespace" />
在下面的示例XML文档中,根元素包含一个将前缀bk映射到命名空间名称http://25hoursaday-com/bookstore的命名空间声明,它的子元素包含一个<inventory>元素。<inventory>元素中包含一个将前缀inv映射到命名空间名称http://25hoursaday-com/inventory-tracking的命名空间声明。
<bk:bookstore xmlns:bk="http://25hoursaday-com/bookstore"> <bk:book> <bk:title>Lord of the Rings</bk:title> <bk:author>J.R.R. Tolkien</bk:author> <inv:inventory status="in-stock" isbn="0345340426" xmlns:inv="http://25hoursaday-com/inventory-tracking" /> </bk:book> </bk:bookstore>
在上例中,http://25hoursaday-com/bookstore命名空间名称的命名空间声明作用域是整个<bk:bookstore>和</bk:bookstore>所包含的具有bk:前缀的元素,而http://25hoursaday- com/inventory-tracking的命名空间声明作用域是inv:inventory元素。能够识别命名空间的处理器可以独立处理来自这两个命名空间的项目,这会使其能够对XML文档执行多层处理。从此示例中,我们已知道,要将某元素与http://25hoursaday-com/bookstore命名空间相关联,只需在该元素名前加上bk:前缀即可。如果想将某个属性(如isbn)和某个命名空间(如http://25hoursaday-com/inventory-tracking)相关联,只需在该属性名前加上前缀,如inv:isbn即可。
除非属性的名称有前缀,否则命名空间声明不应用于属性。在下面的XML文档中,title属性属于<bk:book>元素且没有命名空间,而bk:title属性将http://25hoursaday-com/bookstore作为其命名空间名称。
<bk:bookstore xmlns:bk="http://25hoursaday-com/bookstore"> <bk:book title="Lord of the Rings, Book 3" bk:title="Return of the King"/> </bk:bookstore>
在下例中,即使指定了一个默认命名空间,title属性仍然没有命名空间,且属于book元素。换句话说,属性不能继承默认命名空间。
<bookstore xmlns="http://25hoursaday-com/bookstore"> <book title="Lord of the Rings, Book 3" /> </bookstore>
在使用命名空间的大多数XML文档中,你会发现经常是定义元素属于一个特定的命名空间,而很少定义属性属于一个特定的命名空间。这样做的原因是,属性总是与一个元素相关联,它们不能脱离元素而独立存在。因此,如果该元素本身就已经属于一个命名空间,则其属性已经是唯一可识别的,没有必要为属性再指定一个命名空间了。
XML文档中声明的命名空间具有有效范围。声明的命名空间的范围起始于声明该命名空间的元素,并应用于该元素的所有内容,直到被具有相同前缀名称的其他命名空间声明所覆盖。在下面的XML文档中,命名空间http://wrox.com/namespaces/applications/hr/config的有效范围是整个文档。
<hr:applicationUsers xmlns:hr="http://wrox.com/namespaces/applications/hr/ config"> <hr:user firstName="Joe" lastName="Fawcett" /> <hr:user firstName="Danny" lastName="Ayers" /> <hr:user firstName="Catherine" lastName="Middleton" /> </hr:applicationUsers>
现在对上面的文档进行修改,将命名空间的声明移到第一个<user>元素上中。
<applicationUsers> <hr:user xmlns:hr="http://wrox.com/namespaces/applications/hr/config" firstName="Joe" lastName="Fawcett" /> <user firstName="Danny" lastName="Ayers" /> <user firstName="Catherine" lastName="Middleton" /> </applicationUsers>
此时,命名空间http://wrox.com/namespaces/applications/hr/config的有效范围只在第一个<user>元素及它的属性和它所包含的子元素上(在这个示例中元素<user>并没有包含子元素)。该命名空间不能使用在元素<applicationUsers>或任何其他<user>元素上。当试图分配前缀hr给这些元素时将导致解析XML错误。设计一个XML文档时,限制命名空间声明的有效范围通常被认为是较好的做法。
Namespaces in XML W3C推荐标准对命名空间进行了约束。
(1)以x、m和l这3个字母序列(采用任何大小写组合)开头的前缀被保留,供XML和XML相关的规范使用。尽管这不是一个严重错误,但绑定此类前缀并不可取。前缀xml根据定义绑定至命名空间名称http://www.w3.org/XML/1998/namespace上。
(2)只有已声明并绑定到命名空间的前缀才能使用。
以下代码违反了上述约束。
<?xml version="1.0"?> <Book xmlns:XmlLibrary="http://www.library.com"> <lib:Title>Sherlock Holmes - I</lib:Title> <lib:Author>Arthur Conan Doyle</lib:Author> </Book>
首先,前缀lib未绑定到命名空间,这将导致解析XML时发生错误。其次,前缀XmlLibrary以“Xml”开头,不可取。
2.创建多个命名空间
许多XML文档使用多个命名空间来组织它们的元素。通常情况下,当需要设计这种方式的XML时,用户有多种选择。其中一个选项是为一些元素指定一个默认的命名空间,而为其他元素定义明确的命名空间。下面的示例XML文档中,在根元素<applicationUsers>中定义了一个默认命名空间和一个明确的命名空间。
<applicationUsers xmlns="http://wrm.com/namespaces/applications/hr/config" xmlns:ent="http://wrm.com/namespaces/general/entities"> <ent:user firstName="Joe" lastName="Fawcett" /> <ent:user firstName="Danny" lastName="Ayers" /> <ent:user firstName="Catherine" lastName="Middleton" /> </applicationUsers>
因为这两个声明是在根元素中,所以它们的有效范围为整个文档。文档中没有任何前缀的元素属于默认的命名空间,而任何具有ent前缀的元素属于明确的命名空间。
如果想避免使用默认的命名空间,可以明确声明两个命名空间,如下所示。
<hr:applicationUsers xmlns:hr="http://wrm.com/namespaces/applications/hr/config" xmlns:ent="http://wrm.com/namespaces/general/entities"> <ent:user firstName="Joe" lastName="Fawcett" /> <ent:user firstName="Danny" lastName="Ayers" /> <ent:user firstName="Catherine" lastName="Middleton" /> </hr:applicationUsers>
声明多个命名空间的方式使用较少,用不同的前缀声明同一个命名空间的,如下所示。
<hr1:applicationUsers xmlns:hr1="http://wrm.com/namespaces/applications/hr/config" xmlns:hr2="http://wrm.com/namespaces/applications/hr/config"> <hr2:user firstName="Joe" lastName="Fawcett" /> <hr2:user firstName="Danny" lastName="Ayers" /> <hr2:user firstName="Catherine" lastName="Middleton" /> </hr1:applicationUsers>
两个前缀hr1和hr2都指向同一个命名空间。文档根元素<applicationUsers>采用hr1前缀,而其他元素使用hr2。这种形式可能不是开发人员需要的,但偶尔会碰到,比如在两个不同的应用程序分别创建XML文档的一部分并独立地选择前缀时。
在声明命名空间时,必须注意不能用相同的前缀指向不同的命名空间,比如:
<hr:applicationUsers xmlns:hr="http://wrm.com/namespaces/applications/hr/config" xmlns:hr="http://wrm.com/namespaces/general/entities"> <hr:user firstName="Joe" lastName="Fawcett" /> <hr:user firstName="Danny" lastName="Ayers" /> <hr:user firstName="Catherine" lastName="Middleton" /> </hr:applicationUsers>
例子中的前缀hr指向不同的命名空间,该文档不是一个格式良好的XML文档。
3.无命名空间
如果范围中没有默认命名空间,便不存在命名空间。默认命名空间是使用xmlns显式声明的命名空间。如果未使用xmlns声明默认命名空间,则不能说元素位于默认命名空间中。在这种情况下,可以说元素位于无命名空间中。当已声明的默认命名空间被取消声明时,也将应用无命名空间。
4.命名空间技术摘要
综上所述,命名空间的应用要注意以下几点。
(1)声明命名空间的范围起始于声明该命名空间的元素,并应用于该元素的所有内容,直至被具有相同前缀名称的其他命名空间声明所覆盖。
(2)带前缀的命名空间和默认命名空间都可以被覆盖。
(3)默认命名空间可以被取消声明。
(4)默认命名空间不直接应用于属性。
(5)仅当显式声明默认命名空间时,该命名空间才存在。如果未声明默认命名空间,则不能说元素位于默认命名空间。
(6)如果范围中没有默认命名空间,便不存在命名空间。