SVG——新一代Web设计及互动媒体的革新
首页 SVG入门 XML教程 XML Namespace命名空间上手指南 - XML命名空间的语法规则

XML Namespace命名空间上手指南 - XML命名空间的语法规则

文章首页
XML Namespace命名空间上手指南
什么是命名空间(Namespace)
XML为什么需要命名空间?
XML命名空间的语法规则
解析器是怎样处理XML命名空间的?
命名空间和DTD
命名空间和XML模式
  命名空间为元素和属性指派URI,以消除同名称所产生的模稜两可。一般说来,来自于同一个XML应用的所有元素和属性,都会被指派到同一个URI;而来自于不同XML应用的元素和属性,所被指派的URI也就不同。URI将元素和属性划分成不重叠的集合。具有相同名称却有不同URI的两个元素,视为不相同;反之,名称和URI都相同者,才是相同的元素。命名空间和XML应用之间,通常是一对一的对应关係,然而,少部份XML应用会使用多个命名空间,来区分该应用中的不同部份。例如,XSL就为XSL转换(XSLT)和XSL-FO,使用了不同的命名空间。

全称名称、前置字与本地部份

  因为URI常含有像是/、%和~这些XML名称里不合法的字元,所以我们用较短的前置字(prefix),像是rdf和xsl,在元素和属性名称中代表这些URI。每个前置字都恰好关联到一个URI。两个名称如果具有代表相同URI的前置字,那么便是在同一个命名空间之中;相反地,若两个名称的前置字关联到不同的URI,那么便是在不同的命名空间中。命名空间中的元素和属性之名称会包含一个冒号(:):

rdf:description
xlink:type
xsl:template
  在:之前的所有东西,称作前置字。而在:之后的所有东西,称作本地部份(localpart)。包含冒号在内的完整名称,称作全称名称(qualified name)、QName或未处理的名称(rawname)。前置字用来辨别元素或属性所归属的命名空间,本地部份则用以识别在该命名空间中的元素和属性。

  在一份包含了SVG与MathML之set元素的文件中,其中一个可能是svg:set元素,而另一个是mathml:set元素。这个区别可减少元素之间的溷淆。在一个将文件转换成XSL-FO的XSLT样规中,XSLT处理器可以将具有xsl前置字的元素,视为一个XSLT指令,而具有fo前置字的,则被视为文字化结果之元素。

  前置字可以由任何除了冒号(:)之外的合法XML名称所组成。以xml三个字元所开头的前置字,会被保留给XML和与它相关的规格所用。除此之外,你可以用任何合宜的方式,作为前置字名称。在XML 1.0中,新加入的一个限制是,本地部份也不可以包含冒号。简言之,冒号在XML中唯一合法的使用方式,是用于在全称名称中,分开命名空间前置字和本地部份。

将前置字连结到URL

  每个全称名称的前置字都必须关联到一个URI。例如,所有XSLT 1.0样规中的XSLT元素,都关联到http://www.w3.org/1999/XSL/TransformURI。另外,惯用的前置字xsl用来代替http://www.w3.org/1999/XSL/Transform这个较长URI。

  要将前置字连结(bind)到命名空间URI的方法:为某个具有全称名称的元素(或它的某个祖先元素)加上一个名为xmlns:prefix的属性。prefix为你真正前置字的名称。例如,rdf:RDF元素的xmlns:rdf属性,将前置字rdf连结到命名空间URIhttp://www.w3.org/TR/REC-rdf-syntax#。

URI惯用法

  你不可以直接使用URI作为前置字。首先,大部份URI中都有的斜线,即不为XML名称的合法字元。然而,直接使用完整的URI,而不使用特定的前置字来代表,有时相当有用。在许多XML邮寄名单和XML文件中,可以看到的一种惯用法是:将URI以大括弧({})括起来,放在名称之前。全称名称xsl:template可被写为{http://www.w3.org/1999/XSL/Transform}template来代替。但是这种方式只在,当URI本身很重要,而前置字并不然时,便于人与人之间的沟通。XML解析器和XSLT处理器皆不会接受,也看不懂这种长格式。
<rdf:RDF xmlns:rdf="http://www.w3.org/TR/REC-rdf-syntax#">
 <rdf:Description about="http://ibiblio.org/examples/impressionists.xml">
  <title> Impressionist Paintings </title>
  <creator> Elliotte Rusty Harold </creator>
  <description>
   A list of famous impressionist paintings organized
   by painter and date
  </description>
  <date>2000-08-22</date>
 </rdf:Description>
</rdf:RDF

  连结的有效范围,包括了连结所声明处的元素以及该元素的内容。xmlns:rdf属性为rdf:RDF元素和它的子元素们声明了前置字rdf。RDF处理器可以认出rdf:RDF和rdf:Description是RDF元素,因为两者都具有一个前置字rdf,该前置字连结到RDF规格书中所定义的特定URI。处理器不会把title、creator、description和date元素当作RDF元素,因为它们并未连结到http://www.w3.org/TR/REC-rdf-syntax#这个URI的前置字。

  前置字的声明,可放在所有使用该前置字的最外层之元素中,或者在任何一个此元素的祖先元素里─这可能是文件的根元素或较低层的元素。例如,要将所有的Dublin Core元素附属于命名空间http://purl.org/dc/,只要在rdf:Description元素里加上一个xmlns:dc属性即可,如同范例3所示。可以这麽做是因为这份文件中所有Dublin Core元素都会出现在一个rdf:Description元素里;但如果文件中这类的元素散佈在各处,那么将命名空间声明放在根元素的起始标签中,可能会方便许多。如果有需要,一个元素可包含多个不同的命名空间声明。

范例3:一份包含RDF和DublinCore的文件。

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
 <catalog>
  <rdf:RDF xmlns:rdf="http://www.w3.org/TR/REC-rdf-syntax#">
   <rdf:Description xmlns:dc="http://purl.org/dc/" about="http://ibiblio.org/examples/impressionists.xml">
    <dc:title> Impressionist Paintings </dc:title>
    <dc:creator> Elliotte Rusty Harold </dc:creator>
    <dc:description>
     A list of famous impressionist paintings organized
     by painter and date
    </dc:description>
    <dc:date>2000-08-22</dc:date>
   </rdf:Description>
 </rdf:RDF>

 <painting>
  <title>Memory of the Garden at Etten</title>
  <artist>Vincent Van Gogh</artist>
  <date>November, 1888</date>
  <description>
   Two women look to the left. A third works in her garden.
  </description>
 </painting>

 <painting>
  <title>The Swing</title>
   <artist>Pierre-Auguste Renoir</artist>
   <date>1876</date>
   <description>
    A young girl on a swing. Two men and a toddler watch.
   </description>
 </painting>

 <!-还有更多代码... -->

</catalog>

  这份文件的DTD可以为dc:description和description元素包含不同的内容模型。一份样规也可以为dc:title和title赋予不同的样式。某个会依照日期来排列这份目录的软体,则会注意date元素,而忽略dc:date元素。

  在这范例中,没有前置字的元素,像是catalog、painting、description、artist和title,并不属于任何命名空间。此外,没有前置字的属性,如前例中rdf:Description元素的about属性,也不属于任何命名空间。若一个属性所在的元素属于http://www.w3.org/TR/REC-rdf-syntax#命名空间,并不足以让该属性本身也属于这个命名空间。唯一让一个属性归属于一个命名空间的方法是,让它有个已声明的前置字,例如xlink:type和xlink:href。

  文件中可对前置字重新定义,让同一个前置字在不同元素里指称不同的命名空间URI。在这种情形下,前置字的声明以最接近祖先元素所声明的为准。但是,在大多数的情形,重新定义前置字是不大好的想法,除了造成溷淆之外,并没有什麽用途。

命名空间UR

  许多XML应用有惯用的前置字。譬如,SVG元素通常会使用前置字svg;RDF元素通常会使用前置字rdf。但是,这些前置字只是习惯用法而已,当你有需要、为求方便,甚至是突发奇想的时候,这些前置字仍然可以改变。当在一个前置字可被使用之前,必须先被连结至一个URI,像是http://www.w3.org/2000/svg或http://www.w3.org/1999/02/22-rdf-syntax-ns#。这些URI并非前置字,它们都已标准化,在URI不变的前提下,前置字可被任意改变。RDF处理器会注意的是URI,而非某个特殊的前置字。只要没人在w3.org网域之外使用w3.org网域内的命名空间URI,而且假设W3C可以监控他们的人使用命名空间的方法,那所有冲突都可避免。

  命名空间URI并不一定要指到一份实际存在的文件或网页。事实上,它们根本不需要用到http协定。它们可能使用其它的,像是mailto这种URI并不指向文件的协定。然而,如果你使用http URI,来定义你自己的命名空间,将规格书文件摆在这个URI上,会是不错的主意。W3C已经受不了接到人们不断告诉他们,他们的规格书中之命名空间URI是个根本不存在的链结,所以,他们乾脆在他们的命名空间URI上,加了一个简单的网页。儘管如此,你没有理由也得这麽做。许多命名空间URI在你使用浏览器浏览时,都会造成「404-NotFounderror」的HTTP错误。命名空间URI纯粹只是形式上的辨别字而已,它们并非某个网页的位址,也不打算让别人链结。

  解析器会逐字比较命名空间URI,即使只是一个不重要的地方,都会被视为定义不同的命名空间。例如,http://www.w3.org/1999/XSL/Transform、http://www.W3.ORG/1999/XSL/Transform、http://www.w3.org/1999/XSL/Transform/和http://www.w3.org/1999/XSL/Transform/index.html可能都指到同一个网页。但是,在XSLT样规中,只有第一个是合法的。如果四种都拿来使用,则会建立四个不同的命名空间。

使用xmlns属性设定预设命名空间

  你通常会知道某个元素的所有内容皆来自于某个XML应用。例如,你很可能在SVG的svg元素里,只找到同样属于SVG的元素。要表示一个不含前置字的元素和所有它的子孙元素,都属于同一个命名空间,你可以在最外层的元素加上不含前置字的xmlns属性:

<svg xmlns="http://www.w3.org/2000/svg"
  width="12cm" height="10cm">
 <ellipse rx="110" ry="130" />
 <rect x="4cm" y="1cm" width="3cm" height="6cm" />
</svg>
  这里虽然没有一个元素有前置字,但svg、ellipse和rect元素都在http://www.w3.org/2000/svg命名空间中。

  属性与元素就完全不同了。预设命名空间只对元素而非对属性有效。在上例里,width、height、rx、ry、x和y属性都不在命名空间中。

  你可以在某个元素中加入一个xmlns属性,来改变预设的命名空间。范例4是一份将预设命名空间设为http://www.w3.org/1999/xhtml的文件。这个命名空间声明套用到这份文件的大多处。但是svg元素也有个xmlns属性,把它自己与它内容的预设命名空间重设成http://www.w3.org/2000/svg。然而,XLink资讯被包含在属性中,所以这个属性必须明确地加上前置字,来表示它位于XLink的命名空间中。

  范例4:一份使用预设命名空间的XML文件。

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xlink="http://www.w3.org/1999/xlink">
 <head><title>Three Namespaces</title></head>
 <body>
  <h1 align="center">An Ellipse and a Rectangle</h1>
  <svg xmlns="http://www.w3.org/2000/svg"
    width="12cm" height="10cm">
   <ellipse rx="110" ry="130" />
   <rect x="4cm" y="1cm" width="3cm" height="6cm" />
  </svg>
  <p xlink:type="simple" xlink:href="/ellipses.html">
   More about ellipses
  </p>
  <p xlink:type="simple" xlink:href="/rectangles.html">
   More about rectangles
  </p>
  <hr/>
  <p>Last Modified May 13, 2000</p>
 </body>
</html>
  预设的命名空间并未套用到具有前置字的元素或属性─它们仍然属于它们的前置字所代表的命名空间。但是,如果一个不具前置字的子元素,属于某个有前置字的元素,则该子元素仍然属于预设命名空间。

为xmlns作属性声明

  若命名空间只用来分辨来自某个XML应用的元素和属性,而不能区分同名称的不同元素时,DTD可以为该应用的主要容器元素加上一个固定值(fixed)xmlns属性,来保证每个东西都在正确的命名空间中,而不需要确实加上xmlns属性。例如,下面的ATTLIST声明将所有svg元素的预设命名空间固定为
http://www.w3.org/2000/:

<!ATTLIST svg xmlns CDATA #FIXED "http://www.w3.org/2000/">
  这允许你在svg元素中忽略xmlns属性。

  文件不一定能利用这种忽略所带来的便利。所需要的是解析器必须能读取DTD。所有解析器都会读取内部DTD子集,并处理任何它们从中找到的ATTLIST声明,但一些不做正确合法性验证的解析器可能因忽略外部DTD子集,而被弄溷。理想上,你应该使用会读取外部DTD子集的正确合法性验证解析器,虽然你可能是在验证功能被关掉的情况下使用它。