在学习一个前端数据可视化库D3.js的过程中涉及到了SVG,而SVG又基于XML,从XML又学到DTD。实际上,DTD可以理解为对XML文件内容和格式的一种约束。对于我原本的目的来说,知道这一点就已经够了,不需要深入了解DTD的创建过程。但是既然已经查了半天资料,干脆就静下心抽出一点时间学一学,反正内容也不算多。
我主要是通过菜鸟教程来对DTD进行学习的 DTD 教程 | 菜鸟教程,还看了一些CSDN和知乎上的文章。
一、简介
文档类型定义(DTD,Document Type Definition)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。说白了就是XML太自由,比如要存储一个人的信息,我写了一个<大帅哥>的标签,你用的却是<大屌丝>标签,在数据交互传时,我们互相都搞不懂标签的意思。这就失去了XML为传输和存储数据而被设计出来的初衷,所以需要对它进行约束和验证,其中一种实现方法就是通过DTD。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。通过 DTD,你的每一个 XML 文件均可携带一个有关其自身格式的描述;独立的团体可一致地使用某个标准的 DTD 来交换数据;你的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据;你还可以使用 DTD 来验证你自身的数据。
二、构建模块
所有的XML文件均由以下5个构建模块构成:
(一)元素
就是由一对标签包住的内容。
在DTD中声明一个元素的格式为:<!ELEMENT element-name (element-content)>
element-name是元素名,也就是这对标签的标签名,而(element-content)是对元素内容的描述,有以下若干种情况:
1.空元素 <!ELEMENT element-name EMPTY>
2.只有PCDATA的元素 <!ELEMENT element-name (#PCDATA)>
3.带有任何内容的元素 <!ELEMENT element-name ANY>
4.带有子元素的元素 <!ELEMENT element-name (child1,child2…)> 子元素在XML中出现的顺序必须和括号中的顺序相同。
5.子元素只出现一次 <!ELEMENT element-name (child)>
6.子元素至少出现一次 <!ELEMENT element-name (child+)>
7.子元素出现0次或多次 <!ELEMENT element-name (child*)>
8.子元素出现0次或1次 <!ELEMENT element-name (child?)>
9.非…即… 比如<!ELEMENT element-name (child1, (child2|child3))> 表示必须包含child1,以及child2和child3中的一个
10.混合型 <!ELEMENT element-name (child1|child2)*>包含0次或多次child1和child2中的一个
(二)属性
属性用来提供元素的一些额外信息,以key=“value”的形式写在开始标签中。
一般来说能用属性表示的地方都可以转换为用元素表示,属性不容易扩展,使用时要多考虑考虑。
DTD中给一个元素声明属性的格式为:
<!ATTLIST element-name attribute-name attribute-type attribute-value>
前两个参数分别是元素名和属性命,attribute-type是属性类型:(下图是从菜鸟教程中截取的)
attribute-value是属性的默认值,有如下几种情况:
1.直接写一个值,表示默认值
2.写成#REQUIRED,表示必须设置该属性,且属性没有默认值
3.写成#IMPLIED,表示该属性没有默认值且为选填,不一定要设置
4.写成#FIXED value,表示该属性为固定值value,创作者必须用这个值
(三)实体
实体是用来定义普通文本的变量。实体引用是对实体的引用,主要是用来处理一些含有特殊意义的字符,当然也可以引用普通文本。
一个实体由三部分构成: 与号 (&), 实体名称, 以及一个分号 (;)。
XML中预定义了5个特殊字符的实体:
< > & ' " 分别表示<, >, &, ', " 这五个符号。
1.内部实体声明
格式为:<!ENTITY entity-name "entity-value">
比如:
声明一个实体 <!ENTITY writer "Da Shuaige">,这个声明的意义是定义一个变量,变量名为writer,变量值为"Da Shuaige"。
然后在XML文件中就可以通过 &writer; 引用该实体,经解析器解析后的数据就是"Da Shuaige"。
2.外部实体声明
格式为:<!ENTITY entity-name SYSTEM "URI/URL">
(四)PCDATA
PCDATA 的意思是被解析的字符数据(parsed character data)。字符数据可以理解为开始标签与结束标签之间的文本。声明为PCDATA表示这些文本会被解析器解析。文本中的标签会被当作标记来处理,而实体会被展开。
如前面所说,被解析的字符数据不应当包含 &、< 或者 > 这些具有特殊含义的字符;需要使用 &、< 以及 > 进行替换。
(五)CDATA
CDATA 的意思是字符数据(character data)。表示不会被解析器解析,即文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
三、例子
声明一个根元素为people的XML文件,里面有若干个子元素person,每个person有name、age两个子元素并且有一个sex属性,sex属性必须填且只能填male或female。
<!DOCTYPE people [
<!ELEMENT people (person*)>
<!ELEMENT person (name,age)>
<!ATTLIST person sex (male|female) #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
四、引入到XML文件中
有两种格式:
1.声明在XML文档中
格式为<!DOCTYPE root-element [element-declarations]> ,写在数据之前即可,如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE people [
<!ELEMENT people (person*)>
<!ELEMENT person (name,age)>
<!ATTLIST person sex (male|female) #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
<people>
<person sex="male">
<name>zhang san</name>
<age>30</age>
</person>
<person sex="female">
<name>li si</name>
<age>50</age>
</person>
</people>
2.作为外部引用
引用某个本地或网络地址的message.dtd文件
格式为<!DOCTYPE root-element SYSTEM "filename"> 或
<!DOCTYPE root-element PUBLIC "dtd-url">