XML命名空间详解

一、命名空间的意义
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没有直接使用前缀

我们上边这个方法可以解决我们所面临的问题,但是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地址,仅从编写的角度上看我们也不会这个干,这玩意太麻烦了!!!

四、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本身并没有意义,可以将它理解为是<u>http://www.atguigu.com/xml/b</u>的一个别名,我们在标签中使用b,就相当于使用这个uri地址。一旦使用了b这个前缀,就代表这个标签是属于<u>http://www.atguigu.com/xml/b</u>这个命名空间下的元素。

我们还可以在一个文档中定义多个命名空间,如下的语法也是没有问题的:

<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">

这里我们指定了两个命名空间而都没有使用前缀,解析器在解析文档时会不知道使用哪个命名空间,所以在一个文档中只能有一个默认的命名空间,其他命名空间必须使用前缀。

 

另附一文进一步理解XML/XSD命名空间解析:

https://www.jianshu.com/p/49d44ffc9f47

    原文作者:zisgood
    原文地址: https://blog.csdn.net/zisgood/article/details/98942674
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞