原创

【XML学习 二】DTD原理及使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://tianmaolin.blog.csdn.net/article/details/80877507

咱要摒弃旧技术,就得了解旧技术(当然这里指的新旧是依然有部分联系的哈,不是截然不同的),我认为原因有二:

  1. 旧的技术有时候不是被全盘抛弃的,新的技术有时候(大多时候)是脱胎于旧技术的,所以了解旧的技术并不算是浪费时间
  2. 了解了旧技术之后,你就会发现痛点,哪里不好用,哪里限制太死,这个时候再学习新技术,对比理解一方面可以加深新技术革新部分的记忆,保持印象深刻。另一方面又可以对这个技术的整体有个认知

说了以上这么多废话,就是想表达,在了解Schema之前,我得搞明白DTD的工作原理。

DTD概述

概念用途

文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。说白了就是对XML文档结构进行定义,检查XML文档到底合不合法。好处有如下几点(3C上如下所说,我略微理解下):

  1. 通过 DTD,您的每一个 XML 文件均可携带一个有关其自身格式的描述。说白了就是有了这个东西在,你的任何一个庞大的XML在给别人看之前,都可以先给人家看看DTD,这样给一个目录让人家阅读起来省事儿。
  2. 通过 DTD,独立的团体可一致地使用某个标准的 DTD 来交换数据。说白了就是几个团队做事情的时候需要交换XML数据,只要使用统一标准的DTD,大家各自的应用程序都能通畅的交换数据。
  3. 而您的应用程序也可使用某个标准的 DTD 来验证从外部接收到的数据。说白了就是从别人那儿获取的数据我得知道符合不符合格式呀,就比如给运维丢一个xml让发上去,人家拿着DTD一验证没事儿,就省去了肉眼人工检查了。
  4. 您还可以使用 DTD 来验证您自身的数据。说白了就是自己写完一个XML,没准儿哪儿丢一个或者多一个闭合尖叫号(我就犯过这错误),可以用DTD来自己验证一遍格式有没有问题。

使用方式

DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。

直接声明在XML中

其实类似于HTML引入CSS和JS,你可以选择直接在html里边用style。DTD也可以直接声明到到XML中。

<!DOCTYPE 根元素 [元素声明]>     //通过这样的方式声明

这里举一个例子如下,要注意的是,中括号内部要将各个元素放进去,收尾要加中括号哦。

<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (name,sex,age,describe)>   //note 元素有四个元素:"name,sex,age,describe"
  <!ELEMENT name     (#PCDATA)>             //元素为 "#PCDATA" 类型
  <!ELEMENT sex      (#PCDATA)>
  <!ELEMENT age      (#PCDATA)>
  <!ELEMENT describe (#PCDATA)>
]>
<note>
  <name>茂神</name>
  <sex></sex>
  <age>24</age>
  <describe>茂神最帅了!</describe>
</note>

作为文件引入XML中

大多数时候其实我们还是采取以下这种方式,这种方式让XML相当干净整洁,只要根元素名对应上就可以了

<!DOCTYPE 根元素 SYSTEM "文件名">

还是不害臊的举上边那个例子吧

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
  <name>茂神</name>
  <sex></sex>
  <age>24</age>
  <describe>茂神最帅了!</describe>
</note>

然后note.dtd文件内容呢如下所示:

  <!ELEMENT note (name,sex,age,describe)>   //note 元素有四个元素:"name,sex,age,describe"
  <!ELEMENT name     (#PCDATA)>             //元素为 "#PCDATA" 类型
  <!ELEMENT sex      (#PCDATA)>
  <!ELEMENT age      (#PCDATA)>
  <!ELEMENT describe (#PCDATA)>

很显然,就是把中括号里边的东西都放到这个文件里来了。

组成结构

那么DTD要想描述XML,就得知道XML有哪些组成模块,这样才能对的上,所有的XML均由以下几部分构成:元素 、属性 、实体 、PCDATA 、CDATA 其中后边三种都是关于文本的,私以为算不上组成结构,应该是对数据内容的描述。元素和属性在上一篇里已经详细讨论过了:传送门 https://blog.csdn.net/sinat_33087001/article/details/80874849 这里重点说一下后边三种。

实体

实体是用来定义普通文本的变量实体引用是对实体的引用。就好比说空格是一个普通文本,那么nbsp算作一个实体,那么&nbsp;就算作一个实体引用。XML预置的5种实体和实体引用:
这里写图片描述

PCDATA

PCDATA 的意思是被解析的字符数据(parsed character data)。可把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。我的理解就是元素的类型,元素中间的文本内容将被解析器检查实体以及标记文本中的标签会被当作标记来处理,而实体会被展开。怎么理解呢,举个例子:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
  <descripe><font color='red'>茂 &nbsp;神</descripe>
</note>

当设定为PCDATA的时候descripe标签内容被解析后,将会显示为:茂  神,也就是说标签内部的标记都被读取了。

CDATA

CDATA 的意思是字符数据(character data)。CDATA 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。其实也算是一种约束,区别于PCDATA来看的,怎么理解呢,还举上边那个个例子:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
  <descripe><font color='red'>茂 &nbsp;神</descripe>
</note>

当设定为CDATA的时候descripe标签内容被解析后,将会显示为:

<font color='red'>茂 &nbsp;神

也就是说标签内部的标记都被原封不动的显示出来了。

DTD使用实战

元素

在一个 DTD 中,元素通过元素声明来进行声明。

元素声明

元素声明有两种方式,区别是最后一位是类别或者元素内容

<!ELEMENT 元素名称 类别>
<!ELEMENT 元素名称 (元素内容)>

元素使用

类型和结构界定

通过第一种方式声明的:<!ELEMENT 元素名称 类别>,这里类别为下边左一栏标识的

类别 举例 描述
EMPTY <!ELEMENT br EMPTY> 例如html里的换行符<br/>空元素,通过EMPTY来标识
(#PCDATA) <!ELEMENT name (#PCDATA)> 只有 PCDATA 的元素通过圆括号中的 #PCDATA 进行声明
ANY <!ELEMENT 元素名称 ANY> 例如<!ELEMENT note ANY>根节点可以包括任意结构
(子元素名称 1) <!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.)> 带一个或多个子元素的元素通过圆括号中的子元素名进行声明

要特别注意:当声明带有一个或多个子元素的元素,这些子元素必须按照相同的顺序出现在文档中

出现次数界定

通过第二种方式声明的:<!ELEMENT 元素名称 (元素内容)>,这里类别为下边左一栏标识的

类别 举例 描述
(子元素名称+) <!ELEMENT note (message+)> 声明最少出现一次的元素,message子元素至少在note元素里出现一次
(子元素名称*) <!ELEMENT note (message*)> 声明出现零次或多次的元素,message子元素可在note元素里出现零次或多次。
(子元素名称?) <!ELEMENT note (message?)> 声明出现零次或一次的元素,message子元素可在note元素里出现零次或一次。
(子元素1|子元素2) <!ELEMENT note (name,(sex|age))> 非既,note元素必须包含name子元素,以及sex或age两个元素之一

混合型内容

<!ELEMENT note (#PCDATA|to|from|header|message)*>

这个就比较厉害了,类型和元素内容的混合使用,并且非既括号中的内容可以出现零次或多次。

属性

属性声明

在 DTD 中,属性通过 ATTLIST 声明来进行声明。

<!ATTLIST 元素名称 属性名称 属性类型 默认值>    //语法结构
<!ATTLIST payment type CDATA "check">       //实例
<payment type="check" />                   //应用到xml中

属性使用

属性的类型和默认值都有一些备选项。

属性类型备选

这里写图片描述
看来属性类型没有PCDATA,也对,没有要解析的标记,直接用CDATA方便些。

属性默认值备选

这里写图片描述
下面解释下四种植的含义:

  • 第一种值:直接给属性一个默认值,如果你没赋值,就用我默认的
  • 第二种#REQUIRED:表示你必须指定属性值,没指定就非法
  • 第三种#IMPLIED:表示无所谓,你指不指定属性值都合法
  • 第四种FIXED value:表示属性值你必须得有,而且还必须是我给出的固定的。也就是说我是规则制定者,要求方,你(XML的编写者)必须按照我的要求来做。

列举属性值

<!ATTLIST 元素名称 属性名称 (en1|en2|..) 默认值>       //语法
<!ATTLIST payment type (check|cash) "cash">        //dtd举例

如果采用了这种列举属性值的语法,那么结果为如下的二选一

<payment type="check" />

或者

<payment type="cash" />

这里有一个疑问,使用列举属性值语法,属性值的属性类型如何判断呢?

实体

实体是用于定义引用普通文本或特殊字符的快捷方式的变量实体引用是对实体的引用。实体可在内部或外部进行声明。

内部实体声明

声明语法

<!ENTITY 实体名称 "实体的值">  //语法

DTD举例

<!ENTITY writer "田茂林">
<!ENTITY copyright "Copyright maolintian">

XML中使用

<author>&writer;&copyright;</author>  //当解析的时候就会展开实体

注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。这里W3C表述应该有误,应该是一个实体引用由这三部分组成,参考MSDN得出的结论,这个困扰了一些时间。

外部实体声明

声明语法

<!ENTITY 实体名称 SYSTEM "URI/URL">

DTD 举例

 //该url地址下包含文字:田茂林
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd"> 
//该url地址下包含文字:Copyright maolintian
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd"> 

XML 中使用

<author>&writer;&copyright;</author>

DTD实战

分析一下DTD的实战举例

<!DOCTYPE tvschedule [
<!ELEMENT tvschedule (channel+)>                //电视节目根元素包括多个频道子元素
<!ELEMENT channel (banner,day+)>                //每个频道子元素都包含一个主题和多个day元素
<!ELEMENT banner (#PCDATA)>                     //每个主题都是PCDATA类型的
<!ELEMENT day (date,(holiday|programslot+)+)>   //每个day元素又包括一个data日期元素,和至少一个日期排班
<!ELEMENT date (#PCDATA)>                       //data日期元素是PCDATA类型的
<!ELEMENT holiday (#PCDATA)>                    //holiday 假期也是PCDATA类型,说明没有具体节目内容
<!ELEMENT programslot (time,title,description?)> //programslot子元素又包括time,title,零次或一次description
<!ELEMENT time (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT description (#PCDATA)>

<!ATTLIST tvschedule name CDATA #REQUIRED>        //tvschedule 必须有属性name
<!ATTLIST channel chan CDATA #REQUIRED>           //channel必须有属性chan
<!ATTLIST programslot vtr  CDATA #IMPLIED>
<!ATTLIST title rating CDATA #IMPLIED>
<!ATTLIST title language CDATA #IMPLIED>
]>

这里有个问题,<!ELEMENT day (date,(holiday|programslot+)+)>这里的(holiday|programslot+)外边已经有“+”号了,里边programslot+还有意义么?

DTD实战就浅尝辄止到这里,明显感觉到一个问题是,元素的类型过少啊,只有PCDATE和CDATA两种,如果我是非文本类型呢?希望在SCHEMA里找到答案。

文章最后发布于: 2018-07-02 08:40:09
展开阅读全文
0 个人打赏
私信求帮助

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie

分享到微信朋友圈

×

扫一扫,手机浏览