级别: 初级 Erik Hennum (ehennum@us.ibm.com), 咨询软件工程师, IBM 公司
2002 年 5 月 01 日 在目前的方法中,DTD 是静态的。结果,DTD 设计者要设法涵盖每种可能性,当这一努力失败时,用户不得不强制他们自己的信息去符合现有类型。Darwin 信息分类体系结构(Darwin Information Typing Architecture (DITA))通过向信息架构设计师及开发人员提供扩展基本 DTD 以涵盖他们的域的能力,从而改变了这种局面。本文向您演示了如何利用可扩展 DITA DTD 来描述信息的新域。
Darwin 信息分类体系结构(DITA)是一种用于可扩展技术信息的 XML 体系结构。一个域可以使用一组其名称和内容模型对于组织或知识领域来说是独一无二的元素来扩展 DITA。架构设计师和作者可以结合来自任何数量的域的元素,从而在获取这些域信息的语义和结构方面具有很高的灵活性和精确性。在这篇概述性文章中,您将了解如何定义您自己的域。
介绍域专门化
在 DITA 中,主题是可处理内容的基本单元。主题为内容提供标题、元数据和结构。有些主题提供非常简单的内容结构。例如,对于所有概念内容,
concept 主题只有一个概念主体。相比之下,
task 主题则清晰地表达了一种可以区分任务内容的各个部分(如先决条件、步骤和结果)的结构。
在大多数情况下,这些主题结构包含的内容元素并不特定于主题类型。例如,概念主体和任务先决条件都允许公共块元素,如
p (段落)和
ul (无序列表)。
域专门化使您能独立于主题类型定义内容元素的新类型。即,您可以从已有的短语和块元素派生出新短语和块元素。您可以在任何允许其基本元素的主题结构内使用专门化的内容元素。例如,因为
p 段落可以出现在概念主体或任务先决条件内,所以专门化的段落也可以出现在其中。
图 1. 可以将专门化的内容插入主题主体内
这里用炊具做了一个类比。您可以将主题看作以不同方式准备食物的各种类型的容器,例如,最常用的平底锅、搅拌器和供烘焙用的碟。内容元素就象装入这些容器的各种原料,如调味品、面粉和鸡蛋。域则象为特定菜肴提供原料的专业食品店。当您在烹饪美墨食物时,您的罐子里可能有来自 carnicería 的口利佐香肠(chorizo),而当您在烹饪意大利食品时,您的罐子里可能有意大利调味饭(risotto)。类似地,当您编写编程语言时,您的主题可能含有来自编程域的元素,或者当您编写 GUI 应用程序时,您的主题里可能含有来自 UI 域的元素。
DITA“有非常广泛的兴趣”,因此您可以根据需要混合各种域。如果您在描述如何编写 GUI 应用程序,那么您的主题可以利用来自编程和 UI 域的元素。您也可以为
您的内容创建新域。例如,提供描述硬件设备元素的新域。您也可以重用别人创建的新域,从而扩展您可以编造的种类。
在更正式的定义中,主题专门化从包含元素开始,自顶向下工作。相反,域专门化从被包含元素开始,自底而上工作。
理解基本域
DITA
域收集了一组用于某些目的的专门化内容元素。实际上,一个域提供一个专门化的词汇表。有了基本 DITA 包,您将会有下列域:
|
域
|
用途
| | 突出显示 | 使用诸如粗体、斜体及等宽字体之类的样式突出显示文本 | | 编程 | 定义语法并给出编程语言的示例 | | 软件 | 描述软件程序的操作 | | UI | 描述软件程序的用户界面 |
在大多数域中,专门化元素为基本元素增添了一些语义。例如,编程域的
apiname 元素使用 API 内名称的语义扩展了基本
keyword 元素。
突出显示域是特例。该域内的元素提供添加了样式化的显示而不是语义或结构化的标记。突出显示样式给作者一种实用方法,用来标记还没定义语义的短语。
通过域提供突出显示样式解决了长期存在的关于发布 DTD 的争论。纯粹主义者认为可以忽略突出显示域来增强应该具有严格语义的文档。而实用主义者认为可以包括突出显示域来为现实世界创作提供富有表现力的灵活性。中间派甚至认为可以在概念文档中包括突出显示域以支持富有表现力的创作,但在引用文档中略去突出显示域以强制严格的语义标记。
更一般地,您可以使用域和主题的任意组合来定义文档。如
泛化域中所示,生成的文档仍然可以互换。
结合现有的主题和域
DITA 包为每种主题类型提供一个 DTD,并提供一个定义所有主题类型的综合 DTD(
ditabase.dtd )。这些 DTD 中的每一个都包含所有预定义的 DITA 域。这样,针对某个提供的 DTD 来编写的主题可以使用所有预定义的域专门化。
DITA DTD 实质上仅仅是一个外壳。实际上在其它模块中定义了元素,而 DTD 包括了这些元素。DITA 通过这些模块提供了创建主题类型和域的新组合的构件。
当向 DITA 安装中添加一个域时,新域提供了额外的模块。您可以使用这些额外的模块来将该域合并到现有的 DTD 或创建新的 DTD。
特别地,由两个文件来实现每个域:
- 一个为域声明
实体的文件。该文件具有
.ent 扩展名。
- 一个为域声明
元素的文件。该文件具有
.mod 扩展名。
例如,假定您在为编程语言创作引用主题。在表示方面,您是一个纯粹主义者,因此您不希望包含突出显示域。在该引用中,也不需要软件或 UI 域。您可以通过定义一个将引用主题同编程域结合而但又不包含其它域的新外壳 DTD 来解决该情况。
外壳 DTD 具有一致的设计模式,该模式有几个良好定义的节。这些节中的指令执行下列操作:
-
为域声明实体。在该方案中,这一节将包含编程域实体:
<!ENTITY % pr-d-dec PUBLIC "-//IBM//ENTITIES DITA Programming Domain//EN"
"programming-domain.ent">
%pr-d-dec;
|
- 为基本内容元素重新定义实体以添加来自该域的专门化内容元素。
这一节对于域专门化来说是至关重要的。这里,设计模式利用了两种实体。每个基本内容元素都有一个
元素实体来标识其自身及其专门化。每个域都提供一个单独的
域专门化实体来列出了它为基本元素提供的专门化。通过结合这两种实体,外壳 DTD 允许将专门化的内容元素作为基本元素在相同的上下文中使用。
在该方案中,
pre 元素实体标识
pre 元素(如在 HTML 中一样,该元素含有预先格式化的文本)及其专门化。编程域提供
pr-d-pre 域专门化实体来为
pre 基本元素列出专门化。相同的模式被用于由编程域专门化的其它基本元素:
<!ENTITY % pre "pre | %pr-d-pre;">
<!ENTITY % keyword "keyword | %pr-d-keyword;">
<!ENTITY % ph "ph | %pr-d-ph;">
<!ENTITY % fig "fig | %pr-d-fig;">
<!ENTITY % dl "dl | %pr-d-dl;">
|
要了解域专门化了哪些内容元素,您可以查看该域的实体声明文件。
-
定义主题元素的
domains 属性来声明文档中所表示的域。
象
class 属性一样,
domains 属性标识相关性。
class 属性标识基本元素,而
domains 属性标识主题内可用的域。每个域都提供一个
域标识实体来在
domains 属性中标识自己。
在该方案中,唯一的主题是
reference 主题。唯一的域是编程域,它由
pr-d-att 域标识实体标识:
<!ATTLIST reference domains CDATA "&pr-d-att;">
|
-
重新定义信息类型实体来指定在主题内嵌套的主题类型。
在该方案中,下面这一节声明了
reference 主题:
<!ENTITY % info-types "reference">
|
-
为包括基本主题在内的主题类型定义元素。
在该方案中,下面这一节包含基本主题和引用主题模块:
<!ENTITY % topic-type PUBLIC "-//IBM//ELEMENTS DITA Topic//EN"
"topic.mod">
%topic-type;
<!ENTITY % reference-typemod PUBLIC "-//IBM//ELEMENTS DITA Reference//EN"
"reference.mod">
%reference-typemod;
|
-
为域定义元素。
在该方案中,下面这一节包含编程域定义模块:
<!ENTITY % pr-d-def PUBLIC "-//IBM//ELEMENTS DITA Programming Domain//EN"
"programming-domain.mod">
%pr-d-def;
|
通常,通过复制现有的 DTD 并且添加或者除去主题或域,实现起来最方便。在该方案中,可以从
reference.dtd 开始,然后除去下面用粗体和突出显示的文本指出的突出显示、软件和 UI 域。
<!--vocabulary declarations-->
<!ENTITY % ui-d-dec PUBLIC "-//IBM//ENTITIES DITA User Interface Domain//EN"
"ui-domain.ent">
%ui-d-dec;
<!ENTITY % hi-d-dec PUBLIC "-//IBM//ENTITIES DITA Highlight Domain//EN"
"highlight-domain.ent">
%hi-d-dec;
<!ENTITY % pr-d-dec PUBLIC "-//IBM//ENTITIES DITA Programming Domain//EN"
"programming-domain.ent">
%pr-d-dec;
<!ENTITY % sw-d-dec PUBLIC "-//IBM//ENTITIES DITA Software Domain//EN"
"software-domain.ent">
%sw-d-dec;
<!--vocabulary substitution-->
<!ENTITY % pre "pre | %pr-d-pre;
| %sw-d-pre;
">
<!ENTITY % keyword "keyword | %pr-d-keyword;
| %sw-d-keyword; | %ui-d-keyword;
">
<!ENTITY % ph "ph | %pr-d-ph;
| %sw-d-ph; | %hi-d-ph;
| %ui-d-ph;
">
<!ENTITY % fig "fig | %pr-d-fig;">
<!ENTITY % dl "dl | %pr-d-dl;">
<!--vocabulary attributes-->
<!ATTLIST reference domains CDATA "
(topic ui-d) (topic hi-d)
(topic pr-d)
(topic sw-d)
">
<!--Redefine the infotype entity to exclude other topic types-->
<!ENTITY % info-types "reference">
<!--Embed topic to get generic elements -->
<!ENTITY % topic-type PUBLIC "-//IBM//ELEMENTS DITA Topic//EN" "topic.mod">
%topic-type;
<!--Embed reference to get specific elements -->
<!ENTITY % reference-typemod PUBLIC "-//IBM//ELEMENTS DITA Reference//EN"
"reference.mod">
%reference-typemod;
<!--vocabulary definitions-->
<!ENTITY % ui-d-def PUBLIC "-//IBM//ELEMENTS DITA User Interface Domain//EN"
"ui-domain.mod">
%ui-d-def;
<!ENTITY % hi-d-def PUBLIC "-//IBM//ELEMENTS DITA Highlight Domain//EN"
"highlight-domain.mod">
%hi-d-def;
<!ENTITY % pr-d-def PUBLIC "-//IBM//ELEMENTS DITA Programming Domain//EN"
"programming-domain.mod">
%pr-d-def;
<!ENTITY % sw-d-def PUBLIC "-//IBM//ELEMENTS DITA Software Domain//EN"
"software-domain.mod">
%sw-d-def;
|

 |

|
创建域专门化
对于某些文档,可能需要内容元素的新类型。在常见的方案中,需要标记有特殊语义的短语。可以通过创建现有内容元素的新的专门化并提供一个域以在主题结构内重用该新内容元素来处理这类需求。
例如,假定您正在为一个类库编写文档。您打算编写通过类、字段及方法来索引该文档的过程。要支持这种处理,需要象下面的示例中那样在主题内容内标记类、字段和方法的名称:
<p>The <classname>String</classname> class provides
the <fieldname>length</fieldname> field and
the <methodname>concatenate()</methodname> method.
</p> |
必须为这些名称定义新的内容元素。因为这些名称是 API 内特殊类型的名称,所以您可以对来自编程域所提供的
apiname 元素的新元素进行专门化。
域的设计模式需要一种缩写来代表域。类库域的合理缩写可以是
cl 。域的标识符包含后跟
-d (表示域)的缩写。
如
结合现有的主题和域中所说明的那样,域需要一个实体声明文件和一个元素定义文件。
编写实体声明文件
实体声明文件由执行下列操作的几节组成:
-
定义域专门化实体。
域专门化实体列出域为基本元素提供的专门化元素。为清晰起见,实体名称由域标识符和基本元素名称组成。域为祖先元素和基本元素提供域专门化实体。
在该方案中,域为
apiname 基本元素和
keyword 祖先元素(它是
apiname 的基本元素)定义了域专门化实体:
<!ENTITY % cl-d-apiname "classname | fieldname | methodname">
<!ENTITY % cl-d-keyword "classname | fieldname | methodname">
|
-
定义域标识实体。
域标识实体列出主题类型以及域和同当前域有相关性的其它域。每个域都由其域标识符来标识。该列表被括在括号里。为清晰起见,实体名称由域标识符和
-att 组成。
在该方案中,类库域和编程域有相关性,后者提供
apiname 元素:
<!ENTITY cl-d-att "(topic pr-d cl-d)"> |
完整的实体声明文件如下:
<!ENTITY % cl-d-apiname "classname | fieldname | methodname">
<!ENTITY % cl-d-keyword "classname | fieldname | methodname">
<!ENTITY cl-d-att "(topic pr-d cl-d)">
|
编写元素定义文件
元素定义文件由执行下列操作的几节组成:
-
为由域引入的元素定义内容元素实体。
这些实体允许其它域从当前域的元素专门化。
在该方案中,类库域按照这一做法以便将来可以添加额外的域。域为三个新元素定义了实体。
<!ENTITY % classname "classname">
<!ENTITY % fieldname "fieldname">
<!ENTITY % methodname "methodname">
|
-
定义元素。
专门化的内容模型必须同基本元素的内容模型一致。即,专门化元素的任何可能的内容都必须是可泛化成基本元素的有效内容。在此限制条件下,任何相当大的变化都是可能的。可以用专门化的元素替换基本内容模型内的元素。可以忽略或要求可选的元素。可以用某个元素的一组专门化来替代多次出现的该元素,等等。
专门化内容模型应该总是通过元素实体而不是直接通过名称来标识元素。这一做法可让其它域将它们的专门化合并进当前域中。
在该方案中,元素有以下简单的字符内容:
<!ELEMENT classname (#PCDATA)>
<!ELEMENT fieldname (#PCDATA)>
<!ELEMENT methodname (#PCDATA)>
|
-
为具有
class 属性的元素定义专门化层次结构。
对于域元素,该属性的值必须以加号开始。域提供的元素应该由域标识符限定。
在该方案中,专门化层次结构包括基本主题提供的
keyword 祖先元素和编程域提供的
apiname 元素:
<!ATTLIST classname class CDATA "+ topic/keyword pr-d/apiname
cl-d/classname ">
<!ATTLIST fieldname class CDATA "+ topic/keyword pr-d/apiname
cl-d/fieldname ">
<!ATTLIST methodname class CDATA "+ topic/keyword pr-d/apiname
cl-d/methodname ">
|
完整的元素定义文件将类似如下:
<!ENTITY % classname "classname">
<!ENTITY % fieldname "fieldname">
<!ENTITY % methodname "methodname">
<!ELEMENT classname (#PCDATA)>
<!ELEMENT fieldname (#PCDATA)>
<!ELEMENT methodname (#PCDATA)>
<!ATTLIST classname class CDATA "+ topic/keyword pr-d/apiname
cl-d/classname ">
<!ATTLIST fieldname class CDATA "+ topic/keyword pr-d/apiname
cl-d/fieldname ">
<!ATTLIST methodname class CDATA "+ topic/keyword pr-d/apiname
cl-d/methodname ">
|
编写外壳 DTD
创建了域文件之后,您可以编写外壳 DTD 来将域同主题和其它域相结合。外壳 DTD 必须包括所有的域相关性。
在该方案中,外壳 DTD 将类库域同概念、引用和任务主题以及编程域相结合。特定于类库域的部分在下面用粗体突出显示:
<!--vocabulary declarations-->
<!ENTITY % pr-d-dec PUBLIC "-//IBM//ENTITIES DITA Programming Domain//EN"
"programming-domain.ent">
%pr-d-dec;
<!ENTITY % cl-d-dec SYSTEM "classlib-domain.ent">
%cl-d-dec;
<!--vocabulary substitution-->
<!ENTITY % pre "pre | %pr-d-pre;">
<!ENTITY % keyword "keyword | %pr-d-keyword; | %cl-d-apiname;">
<!ENTITY % ph "ph | %pr-d-ph;">
<!ENTITY % fig "fig | %pr-d-fig;">
<!ENTITY % dl "dl | %pr-d-dl;">
<!ENTITY % apiname "apiname | %cl-d-apiname;">
<!--vocabulary attributes-->
<!ATTLIST concept domains CDATA "&pr-d-att; &cl-d-att;">
<!ATTLIST reference domains CDATA "&pr-d-att; &cl-d-att;">
<!ATTLIST task domains CDATA "&pr-d-att; &cl-d-att;">
<!--Redefine the infotype entity to exclude other topic types-->
<!ENTITY % info-types "concept | reference | task">
<!--Embed topic to get generic elements -->
<!ENTITY % topic-type PUBLIC "-//IBM//ELEMENTS DITA Topic//EN" "topic.mod">
%topic-type;
<!--Embed topic types to get specific topic structures-->
<!ENTITY % concept-typemod PUBLIC "-//IBM//ELEMENTS DITA Concept//EN"
"concept.mod">
%concept-typemod;
<!ENTITY % reference-typemod PUBLIC "-//IBM//ELEMENTS DITA Reference//EN"
"reference.mod">
%reference-typemod;
<!ENTITY % task-typemod PUBLIC "-//IBM//ELEMENTS DITA Task//EN" "task.mod">
%task-typemod;
<!--vocabulary definitions-->
<!ENTITY % pr-d-def PUBLIC "-//IBM//ELEMENTS DITA Programming Domain//EN"
"programming-domain.mod">
%pr-d-def;
<!ENTITY % cl-d-def SYSTEM "classlib-domain.mod">
%cl-d-def; |
注意:将类库短语添加到
keyword 和
apiname 的元素实体。这一添加使得可以在允许关键字的主题结构内而不仅仅在显式允许 API 名称的主题结构内可以用类库短语。事实上,
reference 主题的结构只指定关键字,但将域专门化实体添加到所有祖先元素中却是一个好的做法。
域专门化考虑事项
当定义主题的新类型或域元素时,请记住主题专门化和域专门化的层次结构必须有所区别。专门化主题不能使用内容模型中的域元素。类似地,域元素只可从基本主题或另外一个域中的元素进行专门化。即,主题和域不能有相关性。要结合主题和域,请使用外壳 DTD。
专门化具有内部结构的元素时 ― 包括
ul 、
ol 和
dl 列表以及
table 和
simpletable ― 应该专门化整个内容元素。独立于整个内容结构创建部分内部结构的特殊类型并没有多大意义。例如,您通常想创建特殊类型的列表而不是为普通
ul 和
ol 列表创建特殊类型的
li 列表项。
决不要从突出显示域的元素进行专门化。这些样式元素没有特定的语义。虽然突出显示样式的格式化好象很方便,但后来您将可能会发现需要更改这种格式化。
如同前面指出的那样,在内容模型中应该使用元素实体而不是文字元素名称。要允许域专门化元素实体是必需的。
内容模型应该允许元素实体可以扩展成列表的可能性。当对元素实体应用修饰符时,应该将元素实体括在括号里。否则,如果实体扩展成列表,修饰符将只对最后那个元素起作用。序列中的元素实体也有同样的问题:
..., ( %classname; ), ...
... ( %classname; )? ...
... ( %classname; )* ...
... ( %classname; )+ ...
... | %classname; | ...
|
如果元素实体已经在列表中,就不需要括号。
泛化域
正如主题一样,专门化内容元素可以被泛化成其祖先元素之一。在前面的方案中,
classname 可以泛化成
apiname ,或者甚至泛化成
keyword 。结果,可以交换或合并使用不同域但有相同主题的文档,而不必泛化主题。
要回到在
理解基本域中所提到的有关突出显示样式的争议,使用突出显示域创作的实用性文档将含有类似下面的短语:
... the <b>important</b> point is ... |
当文档被泛化成同一主题但却没有突出显示域时,实用的
b 元素变成纯粹主义者的
ph 元素,这表明在未引入表示的情况下该短语将是特殊的:
... the <ph class="+ topic/ph hi-d/b ">important</ph> point is ... |
在前面的方案中,类库作者可以将他们的主题发送给另外一个没有类库域的 DITA 工作室。接收方将泛化类库主题,将
classname 元素转换成
apiname 基本元素。泛化之后,接收方可以象编辑和处理任何其它 API 名称一样编辑和处理类、字段和方法名称。即,这种情况就好象发送方决定不区分类、字段和方法名称,而是将这些名称标记为一般 API 名称。
作为替代,接收方可以决定将类库域添加到他们的定义中。在这一方法中,发送方将不仅提供他们的主题,而且也将提供域的实体声明和元素定义文件。接收方将把类库域添加到他们的外壳 DTD。接下来,接收方不必泛化就可以使用
classname 元素。
接收方可以使用额外的域而不影响互操作性。即,接收方的外壳 DTD 可以比发送方的外壳 DTD 使用更多域而无需创建修改主题的需求。
注:定义专门化时,应当避免在不能很好地后退到基本元素处理的特殊处理上引入相关性。在该方案中,
classname 元素的特殊处理可能会在输出中生成一个文字“class”标签以节省一点输入并生成一致的标签。然而,在自动实行泛化之后,
apiname 元素的基本处理将不提供该标签。因此,这种相关性将需要特殊的泛化转化来将文字“class”标签附加到源文件中的
classname 元素。
结束语
通过主题专门化和域,DITA 提供了如下优点:
-
更简单的主题设计:文档设计者可以把精力集中在主题的结构之上,而无需预见结构内使用的每一种内容。
-
更简单的主题层次结构:文档设计者可以添加内容的新类型,而无需添加主题的新类型。
-
现有主题的可扩展内容:文档设计者可以使用内容的新类型重用主题现有的类型。
-
语义精确:可以从现有元素派生出具有更具体语义的内容元素,并可以在文档内自由使用这些内容元素。
-
对于作者,元素列表变得更简单:文档设计者可以选择一些域来使元素集最小化。作者可以了解适合于文档的元素而不是学会忽略不需要的元素。
简而言之,DITA 域特性在扩展和重用信息类型方面提供了极大的灵活性。基本 DITA 发行版所提供的突出显示、编程和 UI 域只是使用 DITA 进行实现的一个开始。
声明
本文档中提供的信息尚未经过 IBM 的任何正式测试,是以“按现状”发布的,不附有任何形式的保证(无论是明示的还是默示的)。对这些信息的使用或对本文档中所描述的任何技术的实现,都由读者负责,并且取决于读者对其进行评估及将其集成到他们操作环境中的能力。试图修改这些技术使之适应他们自己环境的读者均需自担风险。
? Copyright International Business Machines Corp., 2002. All rights reserved.
参考资料
关于作者  | |  | Erik Hennum 从事 User Assistance for the IBM Storage Systems Group 的设计与实现。他在以前所做出的贡献包括设计和开发基于 Web 的系统以使生动活泼的示例同注释过的源代码保持同步。他好象获得过哈佛大学英国文学专业学士学位。可以通过
ehennum@us.ibm.com和他联系。
|
对本文的评价
|