XML学习笔记(DTD约束)

1. XML语法

在说明DTD约束前,先介绍XML的基本语法:
文档声明

<? 版本信息[编码信息][文档独立信息]?>
例:<?xml version="1.0" encoding="utf-8" standalone="yes"?>

元素定义:
由开始标记、属性、元素内容、结束标记构成

例:<城市>清远</城市>

属性定义:
一个个元素中可以有多个属性

例:<售价 单位="元">68</售价>

注释:<!-- 这里写注释内容 -->

DTD约束

DTD约束是早期出现的一种XML约束模式语言,根据它的语法创建出来的文件称为DTD文件。

DTD的引入方式:

外部式:

  1. <!DOCTYPE 根元素名称 SYSTEM “外部DTD文件的URL”>
  2. <!DOCTYPE 根元素名称 PUBLIC “DTD名称” “外部DTD文件的URL”>

用一个例子来解释如何使用外部式引入DTD

book.dtd文件
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
book.xml文件
<?xml version="1.0" encoding="utf-8"?>
<!-- 这里引入book.dtd对book.xml进行约束 -->
<!DOCTYPE 书架 SYSTEM "book.dtd">
<书架>
    <书>
        <书名>***</书名>
        <作者>***</作者>
        <售价>10</售价>
    </书>
    <书>
        <书名>****</书名>
        <作者>****</作者>
        <售价>100</售价>
    </书>
</书架>

内嵌式:直接将DTD约束写在XML文档中

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE 书架 [
    <!ELEMENT 书架 (书+)>
    <!ELEMENT 书 (书名,作者,售价)>
    <!ELEMENT 书名 (#PCDATA)>
    <!ELEMENT 作者 (#PCDATA)>
    <!ELEMENT 售价 (#PCDATA)>
]>
<书架>
    <书>
        <书名>***</书名>
        <作者>***</作者>
        <售价>10</售价>
    </书>
    <书>
        <书名>****</书名>
        <作者>****</作者>
        <售价>100</售价>
    </书>
</书架>

DTD语法

DTD的结构一般由元素类型定义、属性定义、实体定义、记号定义等构成

  1. 元素定义:每一条<!ELEMENT ...>语句定义一个元素
<!ELEMENT 元素名称 元素内容>

       在上面定义格式中,元素名称是自定义的;元素内容是对元素包含内容的声明,包括数据类型和符号两部分,它共有5中形式:

  • #PCDATA:表示元素中嵌套的内容是普通字符串,其中,关键字PCDATA是ParsedCharacter Data的简写。例如,<!ELEMENT 书名 (#PCDATA)> 表示书名所嵌套的内容是字符串类型。
  • 子元素:说明元素包含的元素。例如:<!ELEMENT 书 (书名,作者,售价)>表示书中要嵌套书名、作者、售价等子元素
  • 混合内容:表示元素既可以包含字符数据,也可以包含子元素。混合数据必须被定义零个或多个,例如:<!ELEMENT 书 (#PCDATA书名) *>表示书中嵌套的子元素书名包含零个或多个,并且书名是字符串文本格式。
  • EMPTY:该元素是一个空元素。使用场景:元素在文档中已经表明了明确含义,就可以在DTD中用关键字 EMPTY 表明空元素。例如:<!ELEMENT br EMPTY>,br是一个没有内容的空元素。
  • ANY:表示元素可以包含任何的字符数据和子元素。例如:<!ELEMENT 联系人 ANY>表示联系人可以包含任何形式的内容。但是在实际开发中,应该尽量避免使用ANY,因为除了根元素外,其他使用ANY的元素都将失去DTD对XML文档的约束效果。

       在定义元素时,元素内容中可以包含一些符号,不同的符号具有不同的作用。具体如下:

  • 问号[?]:表示该对象可以出现0次或1次
  • 星号[*]:表示该对象可以出现0次或多次
  • 加号[+]:表示该对象可以出现1次或多次
  • 竖线[|]:表示在列出的对象中选择1个
  • 逗号[,]:表示对象必须按照指定的顺序出现
  • 括号[()]:用于给元素进行分组
  1. 属性定义:基本语法格式如下
<!ATTLIST 元素名
    属性名1 属性类型 设置说明
    属性名2 属性类型 设置说明
    ......
>

       在上面属性定义的语法格式中,”元素名“是属性所属元素的名字,”属性名“是属性的名称,”属性类型“则用来指定该属性属于那种类型,”设置说明“用来说明该属性是否必须出现。关于”属性类型“和”设置说明“的相关讲解如下:
2.1. 设置说明:定义元素的属性时,有4中设置说明可以选择

设置说明 含义
#REQUIRED 表示元素的该属性是必须的,例如,当定义联系人信息的DTD时,我们希望每一个联系人都有一个联系电话属性,这时,可以在属性声明时使用REQUIRED
#IMPLED 表示元素可以包含该属性,也可以不包含该属性。例如,当定义一本书的信息时,发现书的页数属性对读者无关紧要,这时,在属性声明时可以使用IMPLIED
#FIXED 表示一个固定的属性默认值,在XML文档中不能将该属性设置为其他值。使用#FIXED关键字时,还需要为该属性提供一个默认值。当XML文档中没有定义该属性时,其值将被自动设置为DTD中定义的默认值
默认值 和FIXED一样,如果元素不包含该属性,该属性将被自动设置为DTD中定义的默认值。不同的是,该属性的值是可以改变的,如果XML文件中设置了该属性,新的属性值会覆盖DTD中定义的默认值

2.2. 属性类型:在DTD中定义元素的属性时,有10种属性类型可以选择,常见的几种属性类型如下

  • CDATA
           这是最常用的一种属性类型,表明属性类型是字符数据,与元素内容说明种的#PCDATA相同。当然,在属性设置值中出现的特殊字符,也需要使用转义字符序列来表示,例如,用”&“表示字符”&“,用”&lt“表示字符”<“等。
  • Enumerated(枚举类型)
           在声明属性时,可以限制属性的取值只能从一个列表中选择,这类属性属于Enumerated(枚举类型)。需要注意的是,在DTD定义中并不会出现关键字Enumerated。案例enum.xml展示如何定义Enumerated类型的属性。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- 内嵌式DTD约束 -->
<!DOCTYPE 购物篮 [
    <!ELEMENT 购物篮 ANY>
    <!-- EMPTY表示肉及不包含字符数据,也不包含子元素,是一个空元素 -->
    <!ELEMENT 肉 EMPTY>
    <!ELEMENT 肉 品种 (鸡肉|牛肉|猪肉|鱼肉) "鸡肉">
]>
<购物篮>
    <肉 品种="鱼肉"/>
    <肉 品种="牛肉"/>
    <肉/>
</购物篮>

       在enum.xml中,“品种”属性的类型是Enumerated,其值只能是“鸡肉、牛肉、猪肉、鱼肉”,而不能使用其他值。“品种”属性的默认值是“鸡肉”,所以,即使<购物篮>元素中的第三个子元素没有显示定义“品种”这个属性,但它实际上也具有“品种”这个属性,且属性的取值为“鸡肉”。

  • ID
           一个ID类型的属性用于唯一标识XML文档中的一个元素。其属性值必须遵守XML名称定义的规则。一个元素只能有一个ID类型的属性,而且ID类型的属性必须设置为#IMPLIED或#REQUIRED。因为ID类型属性的每一个取值都是用来标识一个特定元素,所以,为ID类型的属性提供默认值,特别是固定的默认值是毫无意义的。
<!-- 例:id.xml -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!ELEMENT 联系人列表 [
    <!ELEMENT 联系人列表 ANY>
    <!ELEMENT 联系人 (姓名,EMAIL)>
    <!ELEMENT 姓名 (#PCDATA)>
    <!ELEMENT EMAIL (#PCDATA)>
    <!ELEMENT 联系人 编号 ID #REQUIRED>
]>
<联系人列表>
    <联系人 编号="id1">
        <姓名>张三</姓名>
        <EMAIL>[email protected]</EMAIL>
    </联系人>
    <联系人 编号="id2">
        <姓名>李四</姓名>
        <EMAIL>[email protected]</EMAIL>
    </联系人>
</联系人列表>

       在 id.xml 中,将元素为<联系人>的编号属性设置为#REQUIRED,说明每个联系人都有一个编号,同时,属性编号的类型为ID,说明编号是唯一的。这样一来,通过编号就可以找到唯一对应的联系人了。

  • IDREF和IDREFS
           在上面的 id.xml 中,虽然张三和李四两个联系人的ID编号是唯一的,但是这两个ID类型的属性没有发挥作用,这时可以使用IDREF类型,使这两个联系人之间建立一种一对一的关系。案例 Idref.xml 展示IDREF的使用:
<!-- 例:Idref.xml 演示如何使用IDREF -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 联系人列表 [
    <!ELEMENT 联系人列表 ANY>
    <!ELEMENT 联系人 (姓名,EMAIL)>
    <!ELEMENT 姓名 (#PCDATA)>
    <!ELEMENT EMAIL (#PCDATA)>
    <!ELEMENT 联系人
              编号 ID #REQUIRED
              上司 IDREF #IMPLIED
    >
]>
<联系人列表>
    <联系人 编号="id1">
        <姓名>张三</姓名>
        <EMAIL>[email protected]</EMAIL>
    </联系人>
    <联系人 编号="id2" 上司="id1">
        <姓名>李四</姓名>
        <EMAIL>[email protected]</EMAIL>
    </联系人>
</联系人列表>

       在 Idref.xml 中,为元素<联系人列表>的子元素<联系人>增加一个名称为上司的属性,并且将该属性的类型设置为IDREF,IDREF类型属性的值必须为一个已经存在的ID类型的属性值。在第二个<联系人>元素中,将“上司”属性设置为第一个联系人的编号的属性值,如此一来,就可以形成两个联系人元素之间的对应关系,即李四的上司是张三。
       IDREF可以是两个元素之间形成一对一的关系,而IDREFS可以是元素之间形成一对多的关系。例如:学生借书(Library.xml)

<!-- Library.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library [
    <!ELEMENT library (books,records)>
    <!ELEMENT books (book+)>
    <!ELEMENT book (title)>
    <!ELEMENT title (#PCDATA)>
    <!ELEMENT records (item+)>
    <!ELEMENT item (data,person)>
    <!ELEMENT data (#PCDATA)>
    <!ELEMENT person EMPTY>
    <!ATTLIST book bookid ID #REQUIRED>
    <!ATTLIST person name CDATA #REQUIRED>
    <!ATTLIST person borrowed IDREFS #REQUIRED>
]>
<library>
    <books>
        <book bookid="b0101">
            <title>xml基础</title>
        </book>
        <book bookid="b0102">
            <title>xml进阶</title>
        </book>
        <book bookid="b0103">
            <title>xml再进阶</title>
        </book>
    </books>
    <records>
        <item>
            <data>2019-12-26</data>
            <person name="李四" borrowed="b0101 b0102"/>
        </item>
        <item>
            <data>2019-12-27</data>
            <person name="李四" borrowed="b0101 b0102 b0103"/>
        </item>
    </records>
</library>

       除了上述的几种属性类型外,DTD约束中还有NMTOKEN、NMTOKENS、NOTITION、ENTITY和ENTITYS几种属性类型。

发布了3 篇原创文章 · 获赞 2 · 访问量 684

猜你喜欢

转载自blog.csdn.net/BB_andB/article/details/103730270