• 探索 DTD 在 XML 中的作用及解析:深入理解文档类型定义


    DTD 是文档类型定义(Document Type Definition)的缩写。DTD 定义了 XML 文档的结构以及合法的元素和属性。

    为什么使用 DTD

    通过使用 DTD,独立的团体可以就数据交换的标准 DTD 达成一致。

    应用程序可以使用 DTD 来验证 XML 数据的有效性。

    内部 DTD 声明

    如果 DTD 在 XML 文件内声明,它必须包裹在 定义内:

    带有内部 DTD 的 XML 文档

    note [
    note (to, from, heading, body)>
    to (#PCDATA)>
    from (#PCDATA)>
    heading (#PCDATA)>
    body (#PCDATA)>
    ]>
    <note>
    <to>Toveto>
    <from>Janifrom>
    <heading>Reminderheading>
    <body>Don't forget me this weekendbody>
    note>

    在 XML 文件中,选择"view source" 以查看 DTD。

    上述 DTD 的解释如下:

    • 定义该文档的根元素为 note
    • 定义 note 元素必须包含四个元素:"to, from, heading, body"
    • 定义 to 元素的类型为 "#PCDATA"
    • 定义 from 元素的类型为 "#PCDATA"
    • 定义 heading 元素的类型为 "#PCDATA"
    • 定义 body 元素的类型为 "#PCDATA"

    外部 DTD 声明

    如果 DTD 在外部文件中声明, 定义必须包含对 DTD 文件的引用:

    带有对外部 DTD 引用的 XML 文档

    note SYSTEM "note.dtd">
    <note>
    <to>Toveto>
    <from>Janifrom>
    <heading>Reminderheading>
    <body>Don't forget me this weekend!body>
    note>

    以下是包含 DTD 的文件 "note.dtd" 的内容:

    note (to, from, heading, body)>
    to (#PCDATA)>
    from (#PCDATA)>
    heading (#PCDATA)>
    body (#PCDATA)>

    DTD - XML 构建模块

    XML 和 HTML 文档的主要构建模块是元素

    XML 文档的构建模块

    从 DTD 的角度来看,所有 XML 文档都由以下构建模块组成:

    • 元素
    • 属性
    • 实体
    • PCDATA
    • CDATA

    元素

    元素是 XML 和 HTML 文档的主要构建模块。

    HTML 元素的示例包括 "body" 和 "table"。XML 元素的示例可能是 "note" 和 "message"。元素可以包含文本、其他元素或为空。空的 HTML 元素的示例包括 "hr"、 "br" 和 "img"。

    示例

    <body>some textbody>
    <message>some textmessage>

    属性

    属性提供有关元素的额外信息。

    属性始终位于元素的开始标记内。属性始终以名称/值对的形式出现。以下是具有有关源文件的附加信息的 "img" 元素的示例

    <img src="computer.gif" />

    实体

    一些字符在 XML 中具有特殊含义,例如小于号(<),它定义了 XML 标记的开始。

    大多数人都知道 HTML 实体: " "。这个 "no-breaking-space" 实体用于在 HTML 文档中插入额外的空格。实体在 XML 解析器解析文档时会被展开。

    以下实体在 XML 中是预定义的:

    • < 代表 <
    • > 代表 >
    • & 代表 &
    • " 代表 "
    • ' 代表 '

    PCDATA

    PCDATA 表示解析的字符数据。

    将字符数据视为 XML 元素的开始标记和结束标记之间找到的文本。

    PCDATA 是解析器将解析的文本。解析器将检查文本中的实体和标记。

    文本内的标记将被视为标记,并且实体将被展开。

    但是,解析的字符数据不应包含任何&、<或>字符;这些需要用分别表示为 & <> 实体。

    CDATA

    CDATA 表示字符数据。

    CDATA 是解析器将不解析的文本。文本内的标记将不被视为标记,并且实体将不被展开。

    DTD - 元素

    在 DTD 中,元素通过 ELEMENT 声明进行声明

    声明元素

    在 DTD 中,XML 元素的声明具有以下语法:

    element-name category>

    或者

    element-name (element-content)>

    空元素

    空元素通过 category 关键字 EMPTY 进行声明:

    element-name EMPTY>

    示例

    br EMPTY>

    XML 示例

    <br />

    具有解析字符数据的元素

    仅包含解析字符数据的元素在括号内使用 #PCDATA 进行声明:

    element-name (#PCDATA)>

    示例

    from (#PCDATA)>

    具有任何内容的元素

    使用 category 关键字 ANY 声明的元素可以包含任意可解析的数据组合:

    element-name ANY>

    示例

    note ANY>

    具有子元素(序列)的元素

    具有一个或多个子元素的元素通过在括号内声明子元素的名称进行声明:

    element-name (child1)>

    或者

    element-name (child1,child2,...)>

    示例

    note (to,from,heading,body)>

    当子元素按逗号分隔在序列中声明时,子元素必须按相同的顺序出现在文档中。在完整声明中,子元素也必须被声明,并且子元素也可以有子元素。 "note" 元素的完整声明如下:

    note (to,from,heading,body)>
    to (#PCDATA)>
    from (#PCDATA)>
    heading (#PCDATA)>
    body (#PCDATA)>

    声明元素的仅出现一次

    element-name (child-name)>

    示例

    note (message)>

    上面的示例声明了子元素 "message" 必须在 "note" 元素内出现一次,且仅一次。

    声明元素至少出现一次

    element-name (child-name+)>

    示例

    note (message+)>

    上面示例中的+号表示子元素 "message" 必须在 "note" 元素内出现一次或多次。

    声明元素出现零次或更多次

    element-name (child-name*)>

    示例

    note (message*)>

    上面示例中的*号表示子元素 "message" 可以在 "note" 元素内出现零次或更多次。

    声明元素出现零次或一次

    element-name (child-name?)>

    示例

    note (message?)>

    上面示例中的?号表示子元素 "message" 可以在 "note" 元素内出现零次或一次。

    声明要么/或内容

    note (to,from,header,(message|body))>

    上面的示例声明了 "note" 元素必须包含一个 "to" 元素、一个 "from" 元素、一个 "header" 元素,以及一个 "message" 或 "body" 元素。

    声明混合内容

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

    上面的示例声明了 "note" 元素可以包含零个或多个解析字符数据、"to"、"from"、"header" 或 "message" 元素的出现。

    DTD - 属性

    在 DTD 中,使用 ATTLIST 声明来声明属性

    声明属性

    属性声明具有以下语法:

    element-name attribute-name attribute-type attribute-value>

    DTD 示例

    payment type CDATA "check">

    XML 示例

    <payment type="check" />

    attribute-type 可以是以下之一:

    • CDATA:值是字符数据
    • (en1|en2|..):值必须是列举列表中的一个
    • ID:值是唯一标识符
    • IDREF:值是另一个元素的标识符
    • IDREFS:值是其他标识符的列表
    • NMTOKEN:值是有效的 XML 名称
    • NMTOKENS:值是有效的 XML 名称的列表
    • ENTITY:值是实体
    • ENTITIES:值是实体的列表
    • NOTATION:值是符号的名称
    • xml::值是预定义的 xml 值

    attribute-value 可以是以下之一:

    • value:属性的默认值
    • #REQUIRED:属性是必需的
    • #IMPLIED:属性是可选的
    • #FIXED value:属性值是固定的

    默认属性值

    square EMPTY>
    square width CDATA "0">

    有效的 XML

    <square width="100" />

    在上面的示例中,“square”元素被定义为一个带有类型 CDATA 的空元素。如果未指定宽度,则其默认值为 0。

    REQUIRED

    语法

    element-name attribute-name attribute-type #REQUIRED>

    示例

    person number CDATA #REQUIRED>

    有效的 XML

    <person number="5677" />

    无效的 XML

    <person />

    如果没有默认值的选项,但仍希望强制属性存在,请使用 #REQUIRED 关键字。

    IMPLIED

    语法:

    element-name attribute-name attribute-type #IMPLIED>

    示例

    contact fax CDATA #IMPLIED>

    有效的 XML:

    <contact fax="555-667788" />

    有效的 XML:

    <contact />

    如果不想强制作者包含属性,并且没有默认值的选项,请使用 #IMPLIED 关键字。

    FIXED

    语法:

    element-name attribute-name attribute-type #FIXED "value">

    示例

    sender company CDATA #FIXED "Microsoft">

    有效的 XML:

    <sender company="Microsoft" />

    无效的 XML:

    <sender company="W3Schools" />

    当希望属性具有固定值而不允许作者更改时,请使用 #FIXED 关键字。如果作者包含其他值,XML 解析器将返回错误。

    列举属性值

    语法

    element-name attribute-name (en1|en2|..) default-value>

    示例

    payment type (check|cash) "cash">

    XML 示例

    <payment type="check" />

    <payment type="cash" />

    当希望属性值是固定一组合法值之一时,请使用列举属性值。

    XML 元素与属性

    在 XML 中,没有规定何时使用属性,何时使用子元素。

    元素与属性的使用

    数据可以存储在子元素中,也可以存储在属性中。

    请看以下示例

    <person sex="female">
    <firstname>Annafirstname>
    <lastname>Smithlastname>
    person>
    <person>
    <sex>femalesex>
    <firstname>Annafirstname>
    <lastname>Smithlastname>
    person>

    在第一个示例中,sex 是一个属性。在最后一个示例中,sex 是一个子元素。这两个示例提供了相同的信息。

    在何时使用属性以及何时使用子元素方面,没有具体的规则。根据我的经验,在 HTML 中使用属性很方便,但在 XML 中应该尽量避免使用。如果信息看起来像是数据,请使用子元素

    以下三个 XML 文档包含完全相同的信息:

    1. 使用了一个 date 属性:
    <note date="12/11/2002">
    <to>Toveto>
    <from>Janifrom>
    <heading>Reminderheading>
    <body>Don't forget me this weekend!body>
    note>
    1. 使用了一个 date 元素:
    <note>
    <date>12/11/2002date>
    <to>Toveto>
    <from>Janifrom>
    <heading>Reminderheading>
    <body>Don't forget me this weekend!body>
    note>
    1. 使用了扩展的 date 元素(这是我喜欢的):
    <note>
    <date>
    <day>12day>
    <month>11month>
    <year>2002year>
    date>
    <to>Toveto>
    <from>Janifrom>
    <heading>Reminderheading>
    <body>Don't forget me this weekend!body>
    note>

    避免使用属性?

    是否应该避免使用属性?

    一些使用属性的问题包括:

    • 属性不能包含多个值(子元素可以)
    • 属性不容易扩展(用于未来更改)
    • 属性不能描述结构(子元素可以)
    • 属性更难以通过程序代码进行操作
    • 属性值不容易与 DTD 进行测试

    如果将属性用作数据的容器,最终会得到难以阅读和维护的文档。尽量使用元素来描述数据。仅在提供与数据无关的信息时使用属性。

    不要像这样使用 XML(这不是 XML 的正确用法)

    <note day="12" month="11" year="2002"
    to="Tove" from="Jani" heading="Reminder"
    body="Don't forget me this weekend!">
    note>

    关于属性规则有一个例外:

    有时会为元素分配 ID 引用。这些 ID 引用可以用于访问 XML 元素,方式类似于 HTML 中的 NAME 或 ID 属性。这个例子演示了这一点:

    <messages>
    <note id="p501">
    <to>Toveto>
    <from>Janifrom>
    <heading>Reminderheading>
    <body>Don't forget me this weekend!body>
    note>
    <note id="p502">
    <to>Janito>
    <from>Tovefrom>
    <heading>Re: Reminderheading>
    <body>I will not!body>
    note>
    messages>

    这些示例中的 ID 只是一个计数器或唯一标识符,用于识别 XML 文件中不同的 note,并不是 note 数据的一部分。

    这里想说的是,元数据(关于数据的数据)应该存储为属性,而数据本身应该存储为元素。

    实体声明

    实体(Entity)被用来定义对特殊字符的快捷方式。实体可以声明为内部或外部。

    内部实体声明

    语法

    entity-name "entity-value">

    示例

    DTD示例

    writer "Donald Duck.">
    copyright "Copyright W3Schools.">

    XML示例

    <author>&writer;©right;author>

    注意:一个实体由三部分组成:一个 & 符号、一个实体名和一个分号。

    外部实体声明

    语法

    entity-name SYSTEM "URI/URL">

    XML示例

    <author>&writer;©right;author>

    DTD示例

    电视节目表DTD

    TVSCHEDULE [
    TVSCHEDULE (CHANNEL+)>
    CHANNEL (BANNER,DAY+)>
    BANNER (#PCDATA)>
    DAY (DATE,(HOLIDAY|PROGRAMSLOT+)+)>
    HOLIDAY (#PCDATA)>
    DATE (#PCDATA)>
    PROGRAMSLOT (TIME,TITLE,DESCRIPTION?)>
    TIME (#PCDATA)>
    TITLE (#PCDATA)>
    DESCRIPTION (#PCDATA)>
    TVSCHEDULE NAME CDATA #REQUIRED>
    CHANNEL CHAN CDATA #REQUIRED>
    PROGRAMSLOT VTR CDATA #IMPLIED>
    TITLE RATING CDATA #IMPLIED>
    TITLE LANGUAGE CDATA #IMPLIED>
    ]>

    报纸文章DTD

    NEWSPAPER [
    NEWSPAPER (ARTICLE+)>
    ARTICLE (HEADLINE,BYLINE,LEAD,BODY,NOTES)>
    HEADLINE (#PCDATA)>
    BYLINE (#PCDATA)>
    LEAD (#PCDATA)>
    BODY (#PCDATA)>
    NOTES (#PCDATA)>
    ARTICLE AUTHOR CDATA #REQUIRED>
    ARTICLE EDITOR CDATA #IMPLIED>
    ARTICLE DATE CDATA #IMPLIED>
    ARTICLE EDITION CDATA #IMPLIED>
    NEWSPAPER "Vervet Logic Times">
    PUBLISHER "Vervet Logic Press">
    COPYRIGHT "Copyright 1998 Vervet Logic Press">
    ]>

    产品目录DTD

    CATALOG [
    AUTHOR "John Doe">
    COMPANY "JD Power Tools, Inc.">
    EMAIL "jd@jd-tools.com">
    CATALOG (PRODUCT+)>
    PRODUCT
    (SPECIFICATIONS+,OPTIONS?,PRICE+,NOTES?)>
    PRODUCT
    NAME CDATA #IMPLIED
    CATEGORY (HandTool|Table|Shop-Professional) "HandTool"
    PARTNUM CDATA #IMPLIED
    PLANT (Pittsburgh|Milwaukee|Chicago) "Chicago"
    INVENTORY (InStock|Backordered|Discontinued) "InStock">
    SPECIFICATIONS (#PCDATA)>
    SPECIFICATIONS
    WEIGHT CDATA #IMPLIED
    POWER CDATA #IMPLIED>
    OPTIONS (#PCDATA)>
    OPTIONS
    FINISH (Metal|Polished|Matte) "Matte"
    ADAPTER (Included|Optional|NotApplicable) "Included"
    CASE (HardShell|Soft|NotApplicable) "HardShell">
    PRICE (#PCDATA)>
    PRICE
    MSRP CDATA #IMPLIED
    WHOLESALE CDATA #IMPLIED
    STREET CDATA #IMPLIED
    SHIPPING CDATA #IMPLIED>
    NOTES (#PCDATA)>
    ]>
    ## 最后
    为了方便其他设备和平台的小伙伴观看往期文章:
    微信公众号搜索:`Let us Coding`,关注后即可获取最新文章推送
    看完如果觉得有帮助,欢迎点赞、收藏、关注
  • 相关阅读:
    python 高级技巧
    CLIP模型原理与代码实现详解
    13Java数组与数组内存图
    关于 爷爷组件传值给爸爸组件 孙子组件又直接把值传给爸爸组件 (个人笔记记录) 外人看不懂就不要看
    【附源码】计算机毕业设计SSM石家庄学院跳蚤市场
    java异常
    信奥中的数学:阶乘
    Lambda求和函数在excel上的应用
    钉钉群机器人撤回信息-实操详细教程
    MySQL-MHA高可用配置及故障切换
  • 原文地址:https://www.cnblogs.com/xiaowange/p/18160894