乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • XML 基础语法

    • XML 概述
    • XML 文档结构
    • XML 元素
    • XML 属性
    • XML 语法规则
    • XML 命名空间
    • XML 注释与处理指令
  • DTD 与文档验证

    • DTD 概述
    • DTD 元素声明
    • DTD 属性声明
    • DTD 实体声明
    • DTD 元素与属性对比
    • DTD 完整示例
  • XML Schema 定义

    • XML Schema 概述
    • XSD 简单类型
    • XSD 复杂类型
    • XSD 命名空间与引用
  • XPath 节点定位

    • XPath 概述
    • XPath 路径表达式
    • XPath 谓词与函数
  • XSLT 转换

    • XSLT 概述
    • XSLT 模板与匹配
    • XSLT 控制结构
    • XSLT 输出控制
  • XML 解析技术

    • XML 解析概述
    • DOM 解析
    • SAX 解析
    • StAX 解析
    • XML 与 Java — JAXP
  • XML 在 Java 中的应用

    • Spring XML 配置
    • MyBatis XML 映射
    • pom.xml 与 Maven
    • web.xml 配置详解
  • 现代数据格式对比

    • XML 与 JSON 对比
    • XML 与 YAML 对比
  • XML 显示与浏览器集成

    • XML 在浏览器中的显示
    • XMLHttpRequest 与 AJAX
    • 服务器端 XML 处理
  • XML 进阶查询与链接

    • XQuery 查询语言
    • XLink 超链接
    • XML 验证工具使用
  • XML Web 服务(选读)

    • XML Web 服务概述
    • SOAP 协议详解
    • WSDL 服务描述
    • RSS 内容聚合
    • RDF 资源描述框架

DTD 完整示例

本章定位 :通过两个贴近真实业务的完整 DTD 设计实例——TV 节目表和报纸文章——把前面三章分散的 DTD 知识点(元素声明、属性声明、实体声明)串联起来,形成"从需求到 DTD"的完整建模能力。

定义与作用

单独的 DTD 语法知识是碎片化的:你记住了 <!ELEMENT>、<!ATTLIST>、<!ENTITY> 怎么写,但面对一个真实需求时仍不知从何下手。

DTD 完整示例 的目的:展示如何从一个真实业务场景出发,识别实体、定义元素内容模型、分配属性、建立 ID/IDREF 关联——最终产出一份可运行、可验证的完整 XML+DTD。

核心原理:DTD 建模的思维流程

图解释 :DTD 建模不是直接写声明,而是从业务需求出发的七步结构化流程。每一步都有明确的决策点,而非拍脑袋。

完整示例一:TV 节目表

场景说明

飞翔科技的内部电视台需要一份 XML 格式的"每周节目表"。 黄俪 负责设计格式,需要包含频道信息、节目时间、演职人员,且多个节目可能引用同一个演员。

DTD 设计

tvschedule.dtd :

<!ELEMENT tvschedule (channel+)>

<!-- 频道 -->
<!ELEMENT channel (name, program+)>
<!ATTLIST channel
  id ID #REQUIRED
>
<!ELEMENT name (#PCDATA)>

<!-- 节目 -->
<!ELEMENT program (title, start_time, end_time, description?, cast?, rating?)>
<!ATTLIST program
  pid ID #REQUIRED
  type (新闻|综艺|电视剧|体育|纪录片) #REQUIRED
  is_rerun (yes|no) "no"
>
<!ELEMENT title (#PCDATA)>
<!ELEMENT start_time (#PCDATA)>
<!ELEMENT end_time (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT rating (#PCDATA)>

<!-- 演职人员(用 IDREF 实现交叉引用) -->
<!ELEMENT cast (actor_ref+)>
<!ELEMENT actor_ref EMPTY>
<!ATTLIST actor_ref
  refid IDREF #REQUIRED
>

<!-- 演员信息(独立定义,可被多个节目引用) -->
<!ELEMENT actors (actor+)>
<!ELEMENT actor (actor_name, actor_role?)>
<!ATTLIST actor
  aid ID #REQUIRED
>
<!ELEMENT actor_name (#PCDATA)>
<!ELEMENT actor_role (#PCDATA)>

设计要点解析 :

  1. 频道 id → ID 类型 :每个频道有唯一标识,channel/@id 用 ID 类型保证唯一性
  2. 节目 type → 枚举 :节目类型固定,用枚举约束防止输入错误
  3. 演员引用 → IDREF :actor_ref/@refid 引用 actor/@aid,一个演员可被多个节目引用,避免数据重复
  4. 默认值 :is_rerun 默认 "no",大多数节目不是重播,减少 XML 编写量

XML 实例

tvschedule.xml (内部 DTD 方式):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tvschedule [
  <!-- 此处贴入 tvschedule.dtd 的全部声明 -->
  <!ELEMENT tvschedule (channel+, actors)>
  <!ELEMENT channel (name, program+)>
  <!ATTLIST channel id ID #REQUIRED>
  <!ELEMENT name (#PCDATA)>
  <!ELEMENT program (title, start_time, end_time, description?, cast?, rating?)>
  <!ATTLIST program
    pid  ID     #REQUIRED
    type (新闻|综艺|电视剧|体育|纪录片) #REQUIRED
    is_rerun (yes|no) "no"
  >
  <!ELEMENT title (#PCDATA)>
  <!ELEMENT start_time (#PCDATA)>
  <!ELEMENT end_time (#PCDATA)>
  <!ELEMENT description (#PCDATA)>
  <!ELEMENT rating (#PCDATA)>
  <!ELEMENT cast (actor_ref+)>
  <!ELEMENT actor_ref EMPTY>
  <!ATTLIST actor_ref refid IDREF #REQUIRED>
  <!ELEMENT actors (actor+)>
  <!ELEMENT actor (actor_name, actor_role?)>
  <!ATTLIST actor aid ID #REQUIRED>
  <!ELEMENT actor_name (#PCDATA)>
  <!ELEMENT actor_role (#PCDATA)>
]>
<tvschedule>
  <!-- 演员名单(在节目表之后,但 DTD 不强制顺序) -->
  <actors>
    <actor aid="A01">
      <actor_name>大翔</actor_name>
      <actor_role>主持人</actor_role>
    </actor>
    <actor aid="A02">
      <actor_name>白歌</actor_name>
      <actor_role>嘉宾</actor_role>
    </actor>
    <actor aid="A03">
      <actor_name>黄俪</actor_name>
      <!-- role 可选,暂无 -->
    </actor>
  </actors>

  <!-- 频道1 -->
  <channel id="C01">
    <name>飞翔科技综合频道</name>
    <program pid="P001" type="新闻">
      <title>每周技术资讯</title>
      <start_time>2026-06-15 08:00</start_time>
      <end_time>2026-06-15 08:30</end_time>
      <description>本周行业动态总览,涵盖 AI、云计算、芯片领域</description>
      <cast>
        <actor_ref refid="A01"/>
        <actor_ref refid="A02"/>
      </cast>
      <rating>8.5</rating>
    </program>
    <program pid="P002" type="综艺">
      <title>码农脱口秀</title>
      <start_time>2026-06-15 20:00</start_time>
      <end_time>2026-06-15 21:00</end_time>
      <cast>
        <actor_ref refid="A01"/>
      </cast>
      <rating>9.2</rating>
    </program>
  </channel>

  <!-- 频道2 -->
  <channel id="C02">
    <name>飞翔科技技术频道</name>
    <program pid="P003" type="体育" is_rerun="yes">
      <title>程序员马拉松回放</title>
      <start_time>2026-06-15 14:00</start_time>
      <end_time>2026-06-15 15:30</end_time>
      <cast>
        <actor_ref refid="A03"/>
      </cast>
    </program>
  </channel>
</tvschedule>

IDREF 交叉引用效果 :大翔(aid=A01)同时出现在 P001 和 P002 两个节目中,修改演员信息只需改一处。

完整示例二:报纸文章

场景说明

飞翔科技的企业内刊用 XML 排版。 小崔 负责定义 DTD,要求支持多篇文章、作者信息独立维护、文章间可相互引用。

DTD 设计

newspaper.dtd :

<!-- 报纸根元素 -->
<!ELEMENT newspaper (metadata, articles, authors)>

<!-- 元信息 -->
<!ELEMENT metadata (paper_name, issue_date, edition)>
<!ELEMENT paper_name (#PCDATA)>
<!ELEMENT issue_date (#PCDATA)>
<!ELEMENT edition (#PCDATA)>

<!-- 文章列表 -->
<!ELEMENT articles (article+)>

<!-- 单篇文章 -->
<!ELEMENT article (headline, subtitle?, byline, body, related_links?)>
<!ATTLIST article
  art_id  ID     #REQUIRED
  section (要闻|技术|人物|评论|副刊) #REQUIRED
  status  (draft|review|published)  "draft"
>
<!ELEMENT headline (#PCDATA)>
<!ELEMENT subtitle (#PCDATA)>

<!-- 署名:引用作者 ID -->
<!ELEMENT byline (author_ref+)>
<!ELEMENT author_ref EMPTY>
<!ATTLIST author_ref
  refid IDREF #REQUIRED
>

<!-- 正文(混合内容:文字 + 引用链接) -->
<!ELEMENT body (#PCDATA | related_article)*>
<!ELEMENT related_article EMPTY>
<!ATTLIST related_article
  refid IDREF #REQUIRED
  description CDATA #IMPLIED
>
<!ELEMENT related_links (related_article*)>

<!-- 作者信息(独立维护) -->
<!ELEMENT authors (author+)>
<!ELEMENT author (full_name, title, department?)>
<!ATTLIST author
  auth_id ID #REQUIRED
>
<!ELEMENT full_name (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT department (#PCDATA)>

设计要点解析 :

  1. 混合内容 :(#PCDATA | related_article)* 允许正文中穿插文章引用链接
  2. 文章状态 :status 属性用枚举区分草稿/审核/已发布,适合内刊的审核流程
  3. 作者与文章分离 :作者用独立 authors 块维护,文章用 IDREF 引用

XML 实例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE newspaper SYSTEM "newspaper.dtd">
<newspaper>
  <metadata>
    <paper_name>乐途日报</paper_name>
    <issue_date>2026-06-15</issue_date>
    <edition>第128期</edition>
  </metadata>

  <authors>
    <author auth_id="AU01">
      <full_name>黄俪</full_name>
      <title>高级编辑</title>
      <department>编辑部</department>
    </author>
    <author auth_id="AU02">
      <full_name>小崔</full_name>
      <title>专栏作者</title>
    </author>
  </authors>

  <articles>
    <article art_id="ART001" section="要闻" status="published">
      <headline>飞翔科技发布智能工单系统 2.0</headline>
      <subtitle>以 AI 驱动,效率提升 300%</subtitle>
      <byline>
        <author_ref refid="AU01"/>
      </byline>
      <body>
        飞翔科技今日正式发布智能工单系统 2.0 版本。
        该系统基于大语言模型实现自动化工单分类与派发。
        相关报道请参见
        <related_article refid="ART002" description="技术深度解析"/>
      </body>
    </article>

    <article art_id="ART002" section="技术" status="published">
      <headline>智能工单系统背后的 AI 技术</headline>
      <byline>
        <author_ref refid="AU02"/>
      </byline>
      <body>
        本文深入解析智能工单系统的核心技术架构,
        包括 NLP 分类模型、知识图谱构建、实时派单算法。
      </body>
    </article>
    <!-- 更多文章... -->
  </articles>
</newspaper>

操作结果

验证项结果
ID 唯一性art_id、auth_id 各不重复,验证通过
IDREF 有效性author_ref/@refid 对应到存在的 auth_id,验证通过
枚举约束section="要闻" 在允许范围内,验证通过
默认值article/@status 省略时默认为 "draft"
混合内容<body> 中文本与 <related_article> 交替出现,验证通过

易错场景

IDREF 引用不存在的 ID

<author_ref refid="AU99"/>  <!-- ID 列表中无 AU99 -->

DTD 验证器会报错:IDREF attribute refid references an unknown ID "AU99"。解决:确保所有 IDREF 指向的元素都已声明且 ID 存在。

多个元素使用相同的 ID 值

<actor aid="A01">...</actor>
<actor aid="A01">...</actor>  <!-- ID 重复! -->

ID 类型要求值在 整个文档 范围内唯一(不仅是同级元素),重复会导致验证失败。

忘记在 DTD 中声明引用目标

<!ELEMENT author_ref EMPTY>
<!ATTLIST author_ref refid IDREF #REQUIRED>
<!-- 忘记声明 author 元素及其 aid 属性 -->

DTD 只校验 IDREF 的语法形式(是否是合法 ID 格式),但 真正的引用完整性校验需要在 XML 实例文档中完成 。确保被引用的元素也在 DTD 中完整声明。

面试考点

考点参考答案要点
给出一个场景(如"学生选课系统"),请设计 DTD识别实体(学生、课程、选课记录)→ 确定层级 → 用 ID/IDREF 建立关联 → 枚举约束课程类型/院系
IDREF 和普通 CDATA 引用有什么区别?IDREF 受 DTD 验证器约束——引用的 ID 必须存在且唯一;CDATA 没有此类约束
混合内容声明的写法?`(#PCDATA
内部 DTD vs 外部 DTD 各适合什么场景?内部 DTD:单文件自包含,适合小规模示例和教学;外部 DTD:多文档共享同一结构,适合企业级应用
上一页
DTD 元素与属性对比