XML详解:第一部分
XML概述
XML是eXtensible Markup Language(可扩展标记语言)的缩写。
XML和HTML一样,都衍生于SGML (Standard Generalized Markup Language,标准通用化标记语言)。
SGML有非常强大的适应性,同时也非常复杂,其复杂程度无法适应网络上的日常应用,以致在小型的应用中难以普及。XML的产生就是为了简化SGML,以便用于更加通用的目的。
W3C于1998年2月批准了XML的1.0版本,XML既具有SGML的强大功能和可扩展性,同时又具有HTML.的简单性。它是一个非常简单的SGML语言,方便普通人的使用。可以认为,XML是SGML的一个子集,而HTML则是SGML的一个应用。
XML只是用来传递数据,它是一种纯文本格式,与平台没有关系。
XML与HTML比较
1、 HTML.将数据和其显示效果混在一起,它是一种表现技术,定义了如何显示信息的标签;而XML文档只是存储了数据和描述了数据之间的关系,没有规定该如何显示数据,即将数据和其显示进行了分离。
2、 HTML.的格式要求比较松散,HTML解释器通常采用尽量解释的机制.这祥容易造成同一个页面在不同的浏览器中可能显示出大不相同的结果;而XML是非常严格的标记语言,例如严格区分大小写等问题。
3、 HTML的标记集合是固定的,你不能在自己的应用中扩展HTML标记;而XML没有提供一组事先已经定义好的标签,只是提供一个标准,人们可以按照这个标准来定义自己专用的标记,所以XML的标记是可无限扩展的,它可以用于描述各种应用领城的数据。
4、 XML允许粒度更新,不必在XML文档每次有局部改变时都发送整个文档内容,只有改变的元索才必须从服务器发送到客户机;HTML不支持类似功能。
HTML规范的最终版本HTML 4.01,HTML目前己经不再是Web标记的标准,它已经被XHTML所取代。XHTML是HTML和XML的混合物,它完全采用XML的语法和规则来编写Web页面。
XML基本语法
文档声明
<?xml version="1.0" encoding="GB2312" standalone="yes" ?>
l XML声明语句从 <?xml 开始,到 ?> 结束;
l 声明语句里必须有version属性,但是encoding和standalone属性是可选的;
l version、encoding、standalone三个属性必须按上述顺序排列;
l version属性值必须是1.0或1.1;
l XML声明必须放在文件的开头,即文件的第一个字符必须是 < ,前面不能有空行或空格,关于这一点,有些解析器不那么严格。
1) version属性
解析器遇到它不能识别的版本时,会拒绝解析。目前只有两个版本1.0或1.1。
这两个版本的标准几乎一样,只是在给元素命名时,对某些Unicode字符采取不同的处理方法,以及在某些主机系统里如何处理行结束符问题上也有不同的规定。
除非你遇到一些Unicode字符在1.0版本里不能使用,否则最好使用1.0版本,因为1.1版本的解析器还支持的不够。
2) encoding属性
Unicode码有两种主要的编码方案:UTF-16和UTF-8。
XML规范规定了所有XML处理器必须内置Unicode编码(即上面的两种编码方案),但世界上很少有文档使用Unicode编码,大多数使用ISO-8859-1、中文使用GB2312、GBK编码。
encoding属性值就是告诉解析器我们的文档采用哪种编码方法,然后XML解析器按正确的编码方法读取文档,并把它们转换为Unicode字符。
如果XML声明中没有设置encoding属性来明确指定文档所用的字符编码方式,则一律以Unicode编码看待。XML解析器通过寻找XML文档开始处的字节顺序标记,能够自动检测出文档中的Unicode编码是UTF-8和UTF-16。如果文档中的字符是以UTF-8或者是UTF-16作为编码,则可以不设置这个属性。
当XML文件使用非Unicode编码时,必须在XML文档声明中指定其字符集编码,而采用Unicode编码时则可以在XML文档声明中省略字符集偏码。
3) standalone属性
standalone属性用于说明文档是否是独立的,如果将其设里为“yes”则表示该文档没有依赖外面的任何文件而可以独立存在,既不需要DTD文件来验证其中的标识是否有效,也不需要XSL、CSS文件来控制其显示外观。standalone的默认属性值为“yes”。
标签、文本、元素
<name>
<first>John</first>
</name>
l <first>是一个开始标签
l </first>是一个结束标签
l <first>John</first>是一个元素
元素的开始标签与结束标签之间的文本称为元素的内容。我们称元素的内容为可解析的字符数据(Parsed Character Data),它的缩写为PCDATA。
<name>元素称之为根元素
元素定义
每个开始标签必须有一个结束标签对应,除非它是一个自封闭标签。
l 标签不能重叠,元素必须正确的嵌套;
l 一个XML文档只能有一个根元素;
l 元素的命名必须遵从XML命名规则;
l XML命名是区分大小写的,HTML不区分;
l XML保留PCDATA里的空白符;
XML命名规则:
l 名字的第一个字符必须是26个字母(包括非拉丁字符)或下划线(_),不可是其他字符或其他标志符(注,不能以“$”符开头,这与Java语言命名不一样);
l 其他字符可以是数字、下划线和句点;
l 名字里不能有空格;
l 名字里不能含有冒号(:),严格说,这个字符是允许的,但是根据XML规范,它是“保留”的。我们尽量不要在文档中使用这个字符,除非我们在文档中使用了名称空间;
l 名字的开始字符不可以是xml,不管它是小写的,大写的,或者大小写混合的;
l 开始符 < 之后紧跟着元素名字,期间不能有空格,但是在元素名与结束符 > 之间可以有空格。
注,元素的这些命名规则同样可以应用到XML中其他对象的命名。
l 在HTML里,单词之间凡是被认为不重要的空白字符都会被从文档中删除。多于一个空格都被认为是没有意义的,因此只保留一个。但我们可以使用一个<pre>标签将这些内容括起来,这样就会原样显示了,注,不能使用 <p> 标签;但如果是在XML里,则会原样显示,注,如果使用IE打开,空白字符还是被删除了,这是因为IE并不是直接显示XML文档,它利用一种称之为XSL的技术,先把XML转换为HTML,然后再显示HTML文档。
l 删除行结束空白符:由于在Windows与Unix上的换行不一样,Windows上是使用回车加换行来表示一行的结束,但Unix却只使用一个换行,所以为了统一,标准是要删除除了一个换行符之外其他空白字符。
l 标记里的空白字符:
比如上面 <name> 标签后面有一个回车换行符,这些空白符是为了使文档更具有可读性,实际上不是数据的一部分。这些增强可读性的空白符又称为额外空白符。XML解析器除了必须所有的空白符传递给应用程序外,还要指示应用程序哪些空白符不属于元素的PCDATA的一部分,而只是额外空白符。这取决于验证文档(DTD或Schema)的定义,如果 <name> 只含有其他元素(没有#PCDATA),则把空白符看作是额外空白符,如果含有#PCDATA或标签混合内容,则把空白字符看作是PCDATA的一部分保留下来。如果单从文档本身而没有使用验证文档,则XML解析器无法判断 <name> 是否含有PCDATA,所以在这种情况,解析器会认为不是额外空白字符。注,这里讨论的是空白字符是指标签里的空白字符,而不包括属性里的行结束符(回车换行符)。
<?xml version="1.0" encoding="UTF-8"?>
<name>
<first>
John
</first>
</name>
DocumentBuilder db = dbf.newDocumentBuilder();
// 文档节点
Document dc = db.parse(new File(
"D:\\eclipse_workspace\\Test\\src\\test.xml"));
// 根节点
Element root = (Element) dc.getChildNodes().item(0);
NodeList nl = root.getChildNodes();// 要节点的所有子节点
Node tmpNode;
for (int i = 0; i < nl.getLength(); i++) {
tmpNode = nl.item(i);
System.out.println("NodeName = " + tmpNode.getNodeName()
+ " NodeValue = " + tmpNode.getNodeValue());
if ("first".equals(tmpNode.getNodeName())) {
String firstContent = tmpNode.getChildNodes().item(0)
.getNodeValue();
for (int j = 0; j < firstContent.length(); j++) {
System.out.print((int) firstContent.charAt(j) + " ");
}
System.out.println();
}
}
输出:
NodeName = #text NodeValue =
NodeName = first NodeValue = null
10 9 9 74 111 104 110 10 9
NodeName = #text NodeValue =
--end
从输出结果可以看出,在没有开启验证的情况下,空白符也会当用节点,从上面的输出可以看出要元素有三个节点,因为 <first> 前后空白符解析器解析成了文本节点;另外,文本节点的内容中去掉了回车符,这是由规范决定的。下面我们使用DTD来忽略 <name> 元素前后的空白文本节点:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT name (first)>
<!ELEMENT first (#PCDATA)>
程序修改如下:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//开启DTD验证,此时XML文档一定要引用DTD,否则抛异常
dbf.setValidating(true);
//再进一步说明忽略额外的空白字符,如果没有开启DTD验证,则不起作用
dbf.setIgnoringElementContentWhitespace(true);
输出结果:
NodeName = first NodeValue = null
10 9 9 74 111 104 110 10 9
--end
属性定义
属性是对标签进一步描述和说明。
在HTML中,属性值可以用双引号、单引号引起来,也可以不使用任何引号。在XML中,属性值一定要用双引号或单引号引起来,否则将被视为错误,属性遵循的命名规范与标签相同。
XML解析器在把属性传递给应用程序之前,先对属性值进行预处理,其中最重要的是删除行结束符并用一个空格行代替。如:
<first attr='some data
goes
here'>
John
</first>
但当XML解析器把attr属性值传递给应用程序时,它只传递以下数据:
some data goes here
什么时候使用属性?
属性占用很少空间,但不像元素那样易于扩展,属性没有层次结构。
如果用户的数据里行结束符很重要,则最好把数据放在元素里,不要放在属性里,因为解析器会删除属性值里所有行结束符。
注释
XML文档与HTML文档的注释方式完全一样,语法如下:
<!-- 注释信息-->
XML声明只能作为XML文件中的第一行,所以不要的把注释放在XML声明之前。
不可在标签里再写注释。
注释不能嵌套使用。
在注释中不能有“--”
HTML有这样一种技巧:即注释里加入脚本代码,这样做的目的是支持老式浏览器的用户,因为这些浏览器并不支持<script>标签,在XML里不能使用这种技巧,文档里的注释是不会传递给应用程序的。
处理指令
处理指令是Processing Instruction的中文翻译,通常简称PI,用来为处理XML文档的应用程序提供指示信息。处理指令以“<?”作为开头,以“?>”作为结尾。
指令不属于文档数据,但是它们会传送给应用程序。
对处理指令并没有很多的规定,基本规定就是,在 <? 后面跟一个应用程序名,这个应用程序执行处理指令,最后一直到结束符 ?> 为此都是希望执行的指令。
注,XML声明语句不是处理指令。它只能放在文档的开头,而指令可以放在文档任何位置。
例如.在某个XML文档中可以包含下面的语句来告诉浏览器使用book.css控制显示效果:<?xml-stylesheet type='text/css' href='book.css'?>
非法的PCDATA字符
< &是XML中的保留字符。
l & &
l < <
l > >
l " "
l ' '
另个还可以使用以下两种方式来代替一个字符,如“江”字的Unicode码为“27743”,所以有如下两种替代方案:
江
江
如果文档里出现大量的 < 和 & 字符,且都使用实体代替,那么这些实体引用会显得臃肿难看,这时我们可以使用CDATA文本段。它告诉XML解析器不要对它进行解析,让它里面的内容保持不变,如:
<name>
<![CDATA[
&<>"'
]]>
</name>
因为CDATA段的出现,不管是在CDATA段内,还是在其他地方,]]>是不允许出现的,如果我们需要这三个字符在一起,只能如下使用:]]>
<?xml version="1.0" encoding="GB2312" ?>
<script>
<![CDATA[
for(0 < 1 && 2 > 1){
alert("Hello,I'm jiang!");
}
]]>
</script>
XML名称空间
名称空间
有时需要将来自不同的文档类型的元素组合到一个XML文档里,但时,两个不同的文档类型经常包含一些名字相同但含义和语义却不相同的元素时,如果此时不加以区别放在一个文档里时,无法区分这两个元素。例如我们可以需要建立这样一个XML文档,它不仅包含他的称呼在内(title)的个人信息,还包含了用XHTML表单表示的个人简历:
<?xml version="1.0"?>
<person>
<name>
<title>Sir</title>
<first>John</first>
<middle>Fitzgerald Johansen</middle>
<last>Doe</last>
</name>
<position>Vice President of Marketing</position>
<résumé>
<html>
<head><title>Resume of John Doe</title></head>
<body>
<h1>John Doe</h1>
<p>John's a great guy, you know?</p>
</body>
</html>
</résumé>
</person>
当根据 <title> 查的元素时,XML无法区分这两个元素,两个会一起查出来,除非预先知道文档的结构,根据文档结构查找其中某个元素。
限定名(QName)=名称空间前缀名 + 本地部分
<?xml version="1.0"?>
<pers:person xmlns:pers="http://www.wiley.com/pers"
xmlns:html="http://www.w3.org/1999/xhtml">
<pers:name>
<pers:title>Sir</pers:title>
<pers:first>John</pers:first>
<pers:middle>Fitzgerald Johansen</pers:middle>
<pers:last>Doe</pers:last>
</pers:name>
<pers:position>Vice President of Marketing</pers:position>
<pers:résumé>
<html:html>
<html:head><html:title>Resume of John Doe</html:title></html:head>
<html:body>
<html:h1>John Doe</html:h1>
<html:p>John's a great guy, you know?</html:p>
</html:body>
</html:html>
</pers:résumé>
</pers:person>
虽然<pers:title>元素前面有一个名称空间前缀,元素名却仍然是<title>
当XML处理器解析文档时,将前缀替换成所关联的URI。
注:在声明名称空间进,选择的URI不需要指向实际的内容,在URI所标识的位置上,可以不存在任何东西。在名称空间声明中的URI,只是形式上的标识符,其唯一的目的是提供一个唯一的名字。
两个内置属性
在声明名称空间时,有两个前缀是不允许使用的,它们是xml和xmlns。xml前缀只能用于XML1.0规范中定义的xml:space和xml:lang属性,前缀xml被定义为与名称空间名字 http://www.w3.org/XML/1998/namespace绑定。前缀xmlns仅仅用于声明名称空间的绑定,它被定义为与名称空间名字 http://www.w3.org/2000/xmlns 绑定。
XML规范中定义了两个内置属性,即space和lang,并以xml作为名称前缀,即xml:space和xml:lang,所以我们自己定义的属性名不能以xml: 作为前缀。
xml:space内置属性则是用于设置应用程序该如何处理解析器传递的空格等字符,它是一个Enumerated类型的属性,值只能是 defualt 和 preserve,defualt表示应用程序可以自行随意处理空格等字符,而preserve 则表示应用程序应该把空格等字符当做普通文本字符处理。默认值为 default 。
<x xml:space="preserve" xml:lang="zh_CN" release-date="2001-08-01"/> ,表示release-date是中国的日期格式,默认为 en。
如果在某个元素中设置了xml:space和xml:lang属性,那么,嵌套在该元素中的子孙元素都将沿袭其设置结果,如果在子孙元素重新设置xml:space和xml:lang属性,那么在子孙元素的范围内采用它们自己的设置结果。
默认名称空间
<?xml version="1.0"?>
<person xmlns="http://www.wiley.com/pers"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<name/>
<xhtml:p>This is XHTML</xhtml:p>
</person>
上面了除了<p>元素属于 xhtml 名称空间外,其于都属于默认名称空间。注,只能有一个默认名称空间,且未指定的元素都属于默认名称空间,除非某个元素有名称前缀。
并不只能在根元素里声明名称空间前缀,也可以在文档的任何一个元素里声明名称空间前缀:
<?xml version="1.0"?>
<person xmlns="http://www.wiley.com/pers">
<name/>
<xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">This is XHTML</xhtml:p>
</person>
还可以把XHTML声明为<p>元素及它的子元素的默认名称空间:
<?xml version="1.0"?>
<person xmlns="http://www.wiley.com/pers">
<name/>
<p xmlns="http://www.w3.org/1999/xhtml">This is XHTML</p>
</person>
虽然http://www.wiley.com/pers 是整个文档的默认名称空间,但是http://www.w3.org/1999/xhtml是<p>元素及它的子元素的默认名称空间。换句话说,名称空间http://www.w3.org/1999/xhtml使名称空间http://www.wiley.com/pers无效,因此后者对<p>元素不起作用。
取消默认名称空间
<?xml version="1.0"?>
<person xmlns="http://www.wiley.com/pers">
<name/>
<p xmlns="http://www.w3.org/1999/xhtml"><name xmlns=""></name></p>
</person>
现在<p>元素里的<name>元素不属于任何名称空间了,也不属性默认名称空间,而且如果它还有子元素的话,它的所有没有前缀的子元素也都不存在于任何名称空间中了,更不属于默认名称空间。
名称空间和属性
因为属性是属于某个元素的,我们很容易就能把它与其他元素具有相同名称的属性区分开来,所以给属性添加名称空间不如给元素添加名称空间那么重要。但如果有必要,仍然可以给属性添加名称空间。
<?xml version="1.0"?>
<person xmlns="http://www.wiley.com/pers">
<name id="25">
<titile>Sir</titile>
</name>
</person>
id 属性不属于任何名称空间,它只是关联到<name>这个元素,但<name>自己是默认名称空间的一部分。
注:一个属性要想在某个名称空间中,必须给该属性地加上名称空间的前缀,没有前缀的属性不在任何的名称空间(包括默认的名称空间)。即使拥有属性的元素在某个名称空间中,没有前缀的属性仍然不在该名称空间或任何其他名称空间中。
如果我们使用前缀,则可以为id指定一个名称空间:
<?xml version="1.0"?>
<a:person xmlns:a="http://www.wiley.com/pers">
<a:name a:id="25">
<a:titile>Sir</a:titile>
</a:name>
</a:person>
上面程序表示 id 属性在http://www.wiley.com/pers名称空间里,关联到的<name>元素也在这个名称空间里。
来自某个特定名称空间里的属性同样可以关联到来自不同名称空间里的元素。如果属性被明确声明在一个名称空间中,我们称这些属性为全局属性。
如果元素或属性属于同一名称空间但前缀不一样时,如果开启了名称空间的支持时,XML解析器将会报错误,默认是没有打开对名称空间的支持。
名称空间和DTD
DTD和名称空间并不相关,当XML处理器在验证文档的有效性时,根本不管元素前缀的含义,只是按照DTD的规范对文档进行有效性验证。所以,如果在DTD中声明的上book元素,而在文档中使用的是bks:book元素,则文档验证失败。如果要对使用名称空间的文档通过DTD的验证,则在DTD验证文档中也需要加上前缀。
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE book [
<!ELEMENT book (bk:title,bk:author)>
<!ATTLIST book xmlns:bk CDATA #REQUIRED>
<!ELEMENT bk:title (#PCDATA)>
<!ELEMENT bk:author (#PCDATA)>
]>
<book xmlns:bk="http://www.sunxin.org/bk">
<bk:title> JSP深入编程</bk:title>
<bk:author>张三</bk:author>
</book>
但我们可以使用默认名称空间来改善这种复杂型,但这样还是不能完全解决冲突的,如果XML文档本身有两个同名的 book 元素,但却是不同结构层次上的两个元素时,在DTD中就不能定义两个名一样的元素,因为DTD本身不像XML那样具有层次结构,所以此时只能加上命名前缀了。
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE book [
<!ELEMENT book (title,author)>
<!ATTLIST book xmlns CDATA #REQUIRED>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
]>
<book xmlns="http://www.sunxin.org/bk">
<title></title>
<author></author>
</book>
所以,DTD是不支持命名空间的,但Schema支持。
DTD(Document Type Definitions 文档类型定义)
如果解析器具有验证功能,我们就可以删除应用程序中内容验证代码,让解析器根据DTD验证XML文档的内容。
文档类型声明
--示例
<?xml version="1.0"?>
<!DOCTYPE name [
<!ELEMENT name (first, middle, last)>
<!ELEMENT first (#PCDATA)>
<!ELEMENT middle (#PCDATA)>
<!ELEMENT last (#PCDATA)>
]>
<name>
<first>John</first>
<middle>Fitzgerald Johansen</middle>
<last>Doe</last>
</name>
<!DOCTYPE name [ ]>
从<!DOCTYPE开始,后面是XML文档的根元素名,它必须与文档里的根元素完全一样,包括它的前缀。这里由于文档的根元素是 <name> ,因此,name出现在 <!DOCTYPE 之后。在根元素之后,有两种方法定义文档类型定义的其余内容,一是元素声明放在DTD声明的“[”与“]”之间,此种为内部定义。还有一种是将部分或全部声明都保存在单独一个文件里,这时需要引用外部DTD文件,引用又分两种方法:
l 系统标识符
l 公共标识符
1) 系统标识符
表明XML文件所遵循的是一个本地或组织内部所编写和使用的DTD文件。由两部分组成,关键字SYSTEM和指向文档位置的URI引用,URI可以是硬盘上的一个文件,也可以是Internet上的一个文件。
<!DOCTYPE name SYSTEM "file:///c:/name.dtd" [ ]>
<!DOCTYPE name SYSTEM "http://wiley.com/hr/name.dtd" [ ]>
<!DOCTYPE name SYSTEM "name.dtd">
上面的“[”与“]”是可选的,表示一部分是在XML文档外定义的,一部分是在“[”与“]”间定义的。
2) 公共标识符
表明该XML文件所遵循的是一个由权威机构制定的、公开提供给特定行业或公众使用的DTD文件,而不是某个组织内部的规范文件。
公共标识实质是一种公认的DTD文件的另一种名称而已。例如,用于Java Web应用程序的配置文件的DTD文件的标识名称为"-//Sum Microsystems,Inc.//DTD Web Application 2.3//EN"。
假如为了规范国内企业的人力资源管理,各企业的代表经过协商制定这个DTD后,如果要引用它,就要用PUBLIC关键字而不是SYSTEM关键字。这个DTD可以存放在某个公共的地方,XML处理程序会根据这个公共标识符按照某种方式去检索DTD,如果XML处理器不能根据名称检索到DTD,就会使用公共标识符串后面的备用URI所指定的DTD文件。
公共标识符的公认的基本结构:
-//Owner//Class Description//Language//Version
对于ISO标准的DTD以“ISO”标准三个字母开头;非ISO标准组织批准的DTD以“+”开头;如果不是标准组织批准的DTD以减号“-”开头,紧跟着开始部分后面的是双斜杠“//”及DTD所有者的名称,在这个名称之后又是双斜杠“//”之后是DTD所描述的文件的说明,最后在双斜杠“//”之后是语言的种类,最后是DTD文件的版本号(可选)。
<!DOCTYPE name PUBLIC "-//Beginning XML,4th Edition//DTD Name Example//EN" "name.dtd">
在公共标识符后,还可以插入一个可选的系统标识符(此时SYSTEM关键字可以省略),这样,当处理器不能解析公共标识符时,可以查找这个文档的副本(大多数处理器不能解析公共标识符)。
当XML解析器验证文档时,使用一个与公共标识符相对应的内置DTD,而不是从网上下载一个副本,这使得Web浏览器可以在本地高速缓存里访问DTD,因而大大减少了处理时间,当开发一个应用程序时,可以使用同样的方法。
解析器在对XML文档进行有效性确认时,通常都需要从该指定的URL下载DTD文件,但是,对于一些已经制定成为了行业标准的DTD文件,一些相应的解释器程序可能已经将它们内嵌进去了,所以在解析时并不一定要到指定的URL进行下载。
--name4.dtd
<!ELEMENT name (first, middle, last)>
<!ELEMENT first (#PCDATA)>
<!ELEMENT middle (#PCDATA)>
<!ELEMENT last (#PCDATA)>
--name4.xml
<?xml version="1.0"?>
<!DOCTYPE name PUBLIC "-//Beginning XML//DTD Name Example//EN" "name4.dtd">
<name>
<first>John</first>
<middle>Fitzgerald Johansen</middle>
<last>Doe</last>
</name>
在这个例子里,验证程序无法解析公共标识符,然而,处理器在验证时利用文档里的URI地址找到了正确的DTD验证文件name4.dtd,所以通过验证。
元素定义
<!ELEMENT name (first, middle, last)>
由三部分组成:
l ELEMENT声明
l 元素名
l 元素内容模型
在XML文档结构中具有不同用途的元素一定不要使用相同的元素名,这样在DTD定义时会引起各元素的混淆。
不允许在DTD中对同一名称定义多次。在元素内容模型中说明的每一个元素也必须有自己的DTD定义,但ELEMENT声明的顺序并不重要。
顺序组合:<!ELEMENT contact (name, location, phone, knows, description)>
选择组合:<!ELEMENT location (address | GPS)>
顺序选择组合:<!ELEMENT location (address | (latitude, longitude)>
只有文本:<!ELEMENT first (#PCDATA)>
混合模式:<!ELEMENT description (#PCDATA | em | strong | br)*>
<description>Jeff <em>4th</em><br/> Jeff <strong>loves</strong>xml</description>
注,混合时如果有#PCDATA类型,则一定要将它放在元素列表的开头。
空内容: <!ELEMENT br EMPTY>
注,没有声明成EMPY的元素内容还是可以为空的,但一旦声明成EMPTY后就一定只能为空。
任意内容:<!ELEMENT description ANY> 如,<middle/>
使用ANY关键字表示任何在DTD中声明的元素都可以作用<description>元素的内容,允许它们按任意顺序、次数现出在<description>元素里,但不允许我们使用没有在DTD中声明的元素。当然除了元素外,还可以出现任何字符数据。
基数:<!ELEMENT name (first+, middle?, last)>
<!ELEMENT contacts (contact*)>
<!ELEMENT location (address* | (latitude, longitude)*)>,不允许address和latitude/longitude同时存在。
<!ELEMENT location (address | (latitude, longitude))*>,允许address和latitude/longitude同时存在,上面的混合模式也是这样的。
(#PCDATA)表示元素中嵌套的内容是普通文本字符串,其中,关健字PCDATA是 Parsed Character Data(被解析的字符数据)的简写,因此,在元素内容中出现的特殊字符需要用相应的预定义实体表示。
属性类型
<!ATTLIST 元素名
属性名1 属性类型属性值约束
属性名2 属性类型属性值约束
……
>
在DTD中定义元素的属性时,可以将属设置成下面10种类型。
1、 CDATA
它表示属性值为普通文本字符串(注,与ELEMENT声明中的PCDATA关键字稍有不同,解析器在解析CDATA时,忽略某些保留字),当然,在属性设置值中出现的特殊字特,也需要使用字符的转义实体来表示,例如,用 <表示字符 <,它是属性的默认值。
2、 ENUMERATED(枚举类型)
属性的类型可以是一组取值的列表,在XML文件中设置的属性值只能是这个列表中的某个值。注意,在DTD定义中并不会出现关键字ENUMERATED,如:
<!ATTLIST 肉品种 (鸡肉|牛肉|猪肉|鱼肉) "鸡肉">
如果没有设置,则为“鸡肉”,如果设置也只能是所列出的四种中的一种。
<!ATTLIST phone kind (Home|Work|Cell|Fax) #IMPLIED>
3、 ID、IDREF和IDREFS
ID表示属性的设里值将用于惟一标识一个XML文件中的某个元素。ID类型的属性值必须声明为#IMPLIED或#REQUIRED,并且ID类型的属性值要在整个XML文档中唯一。
使用关健字IDREF作为属性类型时,一个元素的IDREF类型的属性设置必须是引用同一个XML文件中的另一个元索的ID类型的属性的设置值;
IDREFS关键字用于表示IDREF的列表类型,一个元素的IDREFS类型的属性设置值必须是同一个XML文件中的另外多个元素的ID类型的属性的设置值,每个ID属性值之间用空格分隔。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 联系人列表 [
<!ELEMENT 联系人列表 ANY>
<!ELEMENT 联系人 (姓名, EMAIL)>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT EMAIL (#PCDATA)>
<!ATTLIST 联系人编号 ID #REQUIRED>
<!ATTLIST 联系人上司 IDREF #IMPLIED>
<!ATTLIST 联系人下属 IDREFS #IMPLIED>
]>
<联系人列表>
<联系人 编号="id1">
<姓名>张三</姓名>
<EMAIL>zhang@126.com</EMAIL>
</联系人>
<!--上司、下属 属性值一定要是ID类型属性出现过的值-->
<联系人 编号="id2"上司="id1"下属="id1 id2">
<姓名>李四</姓名>
<EMAIL>li@126.com</EMAIL>
</联系人>
</联系人列表>
4、 NMTOKEN和NMTOKENS
nmtoken是Name Token的简写,中文意思就是名称记号,它表示由一个或多个字母、数字、句点“.”、连字号“-”或下划线“_”所组成的一个名称。名称不能为留空,即nmtoken类型的属性值一定要有,且不能包含空白字符。
当使用编程语言处理 XML 数据时,证明了 NMTOKEN 的价值。除了允许使用冒号以外,上述规则与 JAVA , JavaScript 和其他程序语言标识符规则基本一致。例如,可在元素中使用 NMTOKEN 属性访问特别的 JAVA 类。那么就应用 JAVA 的 API 映射把数据传送到专有类的特有方法中。
<!DOCTYPE 联系人列表 [
<!ELEMENT 联系人列表 ANY>
<!ELEMENT 用户 EMPTY>
<!ATTLIST 用户姓名 NMTOKEN #REQUIRED>
<!ELEMENT 数据 EMPTY>
<!ATTLIST 数据授权用户 NMTOKENS #IMPLIED>
]>
<联系人列表>
<用户 姓名=":1a_.-"/>
<数据 授权用户=":2b_.- 1"/>
</联系人列表>
5、 NOTATION
定义非XML格式的数据。如图像、声音等,XML无法直接处理,但可以设置NOTATION类型的属性来让一个外部应用程序进行处理。NOTATION类型的的属性值为在DTD中使用<!NOTATION...>语句中定义的一个notation(符号)。notation定义语句分为两种情况:
<!NOTATION 符号名 SYSTEM "MIME类型">
<!NOTATION 符号名 SYSTEM "URL路径名">
第一种指定数据的MIME类型,第二种指定处理程序的URL路径。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 文件 [
<!NOTATION mp SYSTEM "movPayer.exe">
<!NOTATION gif SYSTEM "image/gif">
<!ELEMENT 文件 ANY>
<!ELEMENT 电影 ANY>
<!ATTLIST 电影演示设备 NOTATION (mp|gif) #REQUIRED>
]>
<文件>
<电影 演示设备="mp"/>
</文件>
6、 ENTITY和ENTITYS
定义实体:<!ENTITY entry "XXXX">
使用关键字ENTITY作为属性的类型时,表明其属性值必须是在DTD中定义过的实体。
<!DOCTYPE 文件 [
<!ENTITY entry "XXXX">
<!ELEMENT 文件 ANY>
<!ATTLIST 文件来源 CDATA #REQUIRED>
]>
<文件 来源="&entry;">&entry;</文件>
只有引用实体才可以作为ENTITY类型的属性的设置值,参数实体不能用做ENTITY类型的属性值。ENTITYS可以引用多个实体,空格分隔。
l 引用实体
在XML文档中使用,两种语法定义:
<!ENTITY 实体名称 "实体内容">
<!ENTITY 实体名称 SYSTEM "外部XML文档的URL">
<!ENTITY 实体名称 PUBLIC "公共标示符" "外部XML文档的URL">
引用方式:&实体名称;
实体内容可以是字符串,也可以XML元素,但这些元素必须是良构的,但不能把根元素插入到替换文本里。另外实体不能引用自己。
如果引用的是第二种定义的实体,则被替换成外部XML文档中的内容。
-- david.txt
Senior Technical Consultant for CGI.
-- jeff.txt
Jeff is a developer & author for Beginning XML <em>4th edition</em> © 2006 Wiley Publishing.<br/>Jeff <strong>loves</strong> XML!
--danny.xml
<description>A Semantic Web developer and technical author specializing in cutting-edge technologies.</description>
--contacts4.dtd
<!ELEMENT contacts (contact*)>
<!ATTLIST contacts version CDATA #FIXED "1.0">
<!ATTLIST contacts source CDATA #IMPLIED>
<!ENTITY source-text "The source of this contacts list is Beginning XML 4E">
<!ELEMENT contact (name, location, phone, knows, description)>
<!ATTLIST contact person ID #REQUIRED>
<!ATTLIST contact tags NMTOKENS #IMPLIED>
<!ELEMENT name (first+, middle?, last)>
<!ELEMENT first (#PCDATA)>
<!ELEMENT middle (#PCDATA)>
<!ELEMENT last (#PCDATA)>
<!ELEMENT location (address | (latitude, longitude))*>
<!ELEMENT address (#PCDATA)>
<!ELEMENT latitude (#PCDATA)>
<!ELEMENT longitude (#PCDATA)>
<!ENTITY address-unknown "The address for this location is "Unknown"">
<!ENTITY empty-gps "<latitude></latitude><longitude></longitude>">
<!ELEMENT phone (#PCDATA)>
<!ATTLIST phone kind (Home | Work | Cell | Fax) "Home">
<!ELEMENT knows EMPTY>
<!ATTLIST knows contacts IDREFS #IMPLIED>
<!ELEMENT description (#PCDATA | em | strong | br)*>
<!ELEMENT em (#PCDATA)>
<!ELEMENT strong (#PCDATA)>
<!ELEMENT br EMPTY>
<!ENTITY jeff-description PUBLIC
"-//Beginning XML//Jeff Description//EN" "jeff.txt">
<!ENTITY david-description PUBLIC
"-//Beginning XML//David Description//EN" "david.txt">
<!ENTITY danny-description PUBLIC
"-//Beginning XML//Danny Description//EN" "danny.xml">
--contacts4.xml
<?xml version="1.0"?>
<!DOCTYPE contacts PUBLIC "-//Beginning XML//DTD Contact Example//EN" "contacts4.dtd">
<contacts source="&source-text;" version="1.0">
<contact person="Jeff_Rafter" tags="author xml poetry">
<name>
<first>Jeff</first>
<first>Craig</first>
<last>Rafter</last>
</name>
<location>
<address>Redlands, CA, USA</address>
<latitude>34.031892</latitude>
<longitude>-117.207642</longitude>
</location>
<phone kind="Home">001-909-555-1212</phone>
<knows contacts="David_Hunter Danny_Ayers"/>
<description>&jeff-description;</description>
</contact>
<contact person="David_Hunter" tags="author consultant CGI">
<name>
<first>David</first>
<last>Hunter</last>
</name>
<location>
<address>&address-unknown;</address>
&empty-gps;
</location>
<phone kind="Work">416 555 1212</phone>
<knows contacts="Jeff_Rafter Danny_Ayers"/>
<description>&david-description;</description>
</contact>
<contact person="Danny_Ayers" tags="author semantics animals">
<name>
<first>Daniel</first>
<middle>John</middle>
<last>Ayers</last>
</name>
<location>
<latitude>43.847156</latitude>
<longitude>10.50808</longitude>
<address>Mozzanella, 7 Castiglione di Garfagnana, 55033 Lucca Italy</address>
</location>
<phone>+39-0555-11-22-33-</phone>
<knows contacts="Jeff_Rafter David_Hunter"/>
&danny-description;
</contact>
</contacts>
l 参数实体
被DTD文件自身使用:
<!ENTITY % 实体名称 "实体内容">
<!ENTITY % 实体名称 SYSTEM "name4.dtd">
<!ENTITY % 实体名称 PUBLIC 公共标识符 "name4.dtd">
引用方式:%实体名称;
如:
<!ENTITY % TAG_NAMES "姓名|EMAIL|电话">
<!ELEMENT 个人信息 (%TAG_NAMES;|生日)>
注,在定义参数实体里我们不能引用那 5个内置的实体,如果需要,我们只能使用字符实体,如:
<!ENTITY % DefaultPhoneKind ""Home"">
<!ATTLIST phone kind (Home | Work | Cell | Fax) %DefaultPhoneKind;>
或者这样:
<!ENTITY % DefaultPhoneKind '"Home"'>
属性值约束
在DTD中定义元素的属性时,可以有下面几种设置说明:
1、#REQUIRED:说明必须设置该属性。
<!ATTLIST phone kind (Home|Work|Cell|Fax) #REQUIRED>
2、#IMPUED:说明可以设置,也可以不设置该属性。
<!ATTLIST knows contacts IDREFS #IMPLIED>
3、#FIXED:说明该属性的取值固定为一个默认值,在XML文件中不能将该属性设置为其他值。使用#FIXED时,还需要为该属性提供一个默认值。
<!ATTLIST contacts version CDATA #FIXED "1.0">
4、直接使用默认值:如果在属性的设置说明部分没有使用上面任何一种关键字,而是直接指定一个默认值的话,那么在XML文件中可以设,也可以不设置该属性。如果XML文件中没有设置该属性,该属性将被自动设置为DTD中定义的默认值;如果XMI.文件中设置了该属性,可以使用新的属性值来覆盖DTD中定义的默认值。
<!ATTLIST phone kind (Home|Work|Cell|Fax) "Home">