基于 XML 的 Darwin Information Typing Architecture (DITA) 的目标是建立便于在各种显示和交付机制中重用的模块化技术文档,比如帮助集合、手册、小屏幕设备中的分级摘要,等等。本文介绍如何将 DITA 基本原理付诸实践,创建支持特定信息类型的 DTD 和转换,而不仅仅使用基本的 DITA 集合,如概念、任务和引用。
主题专门化是作者和架构师定义新的主题类型同时保持与已有样式表、转换、过程兼容的过程。新的主题类型可以作为相对于已有主题类型的扩展或者修订来定义,从而减少定义和维护新类型的工作量。
本文假设您知道 DITA 是什么,否则请参阅本系列的入门文章 Darwin 信息类型化体系结构简介。本文中的例子使用 XML DTD 语法和 XSLT,如果不熟悉这些主题请参阅 参考资料。
在 SGML 中,体系结构表单是提供从一种文档类型到另一种文档类型映射的传统方法。专门化是针对一种约束更强问题的类体系结构表单解决方案:提供从更具体的主题类型到更一般主题类型的映射。因为特殊的主题类型是从头脑中一般的主题类型发展起来的,所以专门化可以忽略体系结构表单要解决的很多棘手问题。这种受限制的领域使得专门化过程相对容易实现和维护。专门化还为多层或分级规范提供了支持,允许更一般的主题类型作为不同特殊类型的公共基础。
专门化过程是随着 DITA 创建的,但其基本原理和过程也适用于其他领域。通过一个例子可能更容易理解:给定专门化和一种一般的 DTD 如 HTML,就可以创建一种新的文档类型(称之为 MyHTML)。在 MyHTML 中可以强制实施公司的站点标准,包括表单布局、标题级别、字体和 blink 标记的使用等的特殊规则。此外,还可以为产品和订购信息提供更具体的结构,使搜索引擎和其他应用程序更有效地使用数据。
专门化使 MyHTML 被定义成 HTML DTD 的一种扩展,只在必要时声明新的元素类型,共同的元素则引用 HTML DTD。无论 MyHTML 在何处声明新的元素,都包括到已有 HTML 元素的映射。这种映射使得为 HTML 创建的样式表和转换同样能用于 MyHTML 文档。若要以不同的方式处理结构(比如用特殊的方式格式化产品信息),可以定义新的样式表或转换来实现这种扩展行为,然后再导入标准样式表或转换来处理其他部分。换句话说,新的行为被作为扩展增加到原来的样式表中,同样,新的约束也被作为扩展增加到原来的 DTD 或模式中。
Darwin Information Typing Architecture 更多的是关于信息类型而不是文档类型的。文档被看作是由一些主题组成,每个主题都有自己的信息类型。简而言之,主题就是包括标题和一些文本的信息块,可能还分解成不同的章节。信息类型描述了主题的内容,比如给定主题的类型可能是 “概念” 或 “任务”。
DITA 有三种类型的主题:一般主题或信息类型化概念、任务和引用主题。概念、任务和引用主题都可以看作是主题的专门化:
图 1. 主题专门化的三种信息类型
新的信息类型可以作为这三种基本类型的专门化或者直接对主题的专门化而增加到该体系结构中,这些新的专门化又可以进一步派生:
图 2. 加入特殊类型的体系结构
每种新的信息类型都被作为已有信息类型的扩展进行定义:专门化的类型继承而不是复制公共结构,专门化类型提供其新元素到一般类型已有元素的映射。每种信息类型都在自己的 DTD 模块中定义,其中仅定义该类型的新元素。只包含一种信息类型的文档(比如网络帮助中的任务文档)的文档类型由信息类型专门化层次结构中的所有模块定义(如 task.mod 和 topic.mod)。包含多种信息类型的文档类型(如包含概念、任务和引用主题的图书)包括使用的每种信息类型及其祖先的模块(concept.mod、task.mod、reference.mod 再加上它们的祖先 topic.mod)。
因为信息类型声明分布在不同的模块中,所以定义信息的信息类型不会影响到祖先类型。这种分隔带来了以下好处:
- 降低维护成本:每个编写团体只需要维护自己特殊的元素。
- 提高兼容性:核心信息类型可以集中维护,对核心类型的修改影响到所有的专门化类型。
- 分散控制:可重用性由以后的用户而不是作者控制,增加新类型不会影响到核心类型的维护,也不会影响不同类型的其他用户。
任何信息类型化的主题都属于多种类型。比如 API 描述从更一般的意义上来说是一种引用主题。
下图是一个引用主题的专门化层次结构:
图 3. 简单的专门化层次结构
表 1 说明了 topic 中的一般元素和 reference 中特殊元素之间的关系。该表中的列、行和单元格表示信息类型、元素映射和元素。表 2 详细阐释了表 1 中的关系。
表 1. 主题及其专门化之间的关系
| 主题 | 引用 |
| (topic.mod) | (reference.mod) |
| topic | reference |
| title | |
| body | refbody |
| simpletable | properties |
| section | refsyn |
表 2. 对表 1 的解释
| 结构 | 关联 |
| 列 | 主题 列显示了基本的 topic 结构,包括 title、body 和可选的 section,在 DTD 模块 topic.mod 中声明。引用 列显示了更特殊的结构,reference 代替了 topic,refbody 代替了 body,refsyn 代替了 section,这些新元素在 DTD 模块 reference.mod 中声明。 |
| 行 | 每一行表示该行中元素之间的一个映射。引用 列中的元素专门化了 主题 列中的元素。每个一般化元素还是同一行中更特殊的元素的类别。比如,reference 的 refsyn 是一种 section。 |
| 单元格 | 列中的每个单元格表示关于该单元格和其左侧单元格的下列可能情况:
|
清单 1 显示的并非真正的 reference.mod 内容,而是基于表 1 的简化版本。如领域专门化一文(请参阅 参考资料)中所述,内容模型中的实体使用支持领域专门化。
清单 1
<!ELEMENT reference ((%title;), (%prolog;)?, (%refbody;),
(%info-types;)* )>
<!ELEMENT refbody (%section; | refsyn | %simpletable; | properties)*>
<!ELEMENT properties ((%sthead;)?, (%strow;)+) >
<!ELEMENT refsyn (%section;)* > |
这里声明的多数内容模型依赖于 topic.mod 中声明的元素或实体。因此,如果 topic 结构改进或变化了,大部分变化会自动反映到 reference 中。此外,reference 的定义仍然很简单,不需要声明与 topic 相同的任何内容。
为了公开元素映射,可以为每个元素增加一个属性用于展示其到一般元素类型的映射。
清单 2
<!ATTLIST reference class CDATA "- topic/topic reference/reference ">
<!ATTLIST refbody class CDATA "- topic/body reference/refbody ">
<!ATTLIST properties
class CDATA "- topic/simpletable reference/properties ">
<!ATTLIST refsyn class CDATA "- topic/section reference/refsyn > |
后面将说明如何在编写 XSLT 转换时利用这些属性。关于 class 属性更深入的讨论请参阅附录。
现在已经定义了类型模块(声明了新的类型化元素及其属性)并增加了专门化属性(将新类型映射到它的祖先),可以组成一个编写 DTD 了。
清单 3
<!--Redefine the infotype entity to exclude other topic types--> <!ENTITY % info-types "reference"> <!--Embed topic to get generic elements --> <!ENTITY % topic-type SYSTEM "topic.mod"> %topic-type; <!--Embed reference to get specific elements --> <!ENTITY % reference-type SYSTEM "reference.mod"> %reference-type; |
现在来介绍如何创建一种更特殊的信息类型:API 描述,这是一种引用主题(或者说引用主题的专门化)。
图 4. 更特殊的信息类型,API 描述
表 3 显示了 API 描述信息类型 APIdesc 专门化的一部分。与以前一样,每一列表示一种信息类型,专门化从左到右依次进行。即每种信息类型都是对左侧邻居的专门化。每一行表示一组映射元素,右侧的特殊元素映射到左侧的一般元素。
同样,单元格是对其左侧单元格内容的专门化:
-
空白单元格:左侧元素不经改变直接供新类型使用。比如,API 描述中可使用
simpletable和refsyn。 -
填充的单元格:左侧的元素用更特殊的元素代替。比如,
APIname代替了title。 -
带有空白单元格的分隔行:新元素增加到左侧的元素上。比如,API 描述增加了
usage节(section)和refsyn以及section元素对应。
表 3. APIdesc 专门化小结
| 主题 | 引用 | APIdesc |
| (topic.mod) | (reference.mod) | (APIdesc.mod) |
| topic | reference | APIdesc |
| title | APIname | |
| body | refbody | APIbody |
| simpletable | properties | parameters |
| section | refsyn | |
| 用法 |
可以看到,与一般引用主题的内容相比,API 描述的内容实际上有更多的限制。现在依次增加了语法、用法、参数以及可选的其他节。这个序列是引用主题所允许结构的一个子集,后者没有规定语法、属性和章节的顺序。此外,用法 section 的标签已利用 section 的 spectitle 属性固定为 Usage(该属性就是用于这类目的的):spectitle 属性提供了 section 标题,也可以在用法内容模型中去掉 title 元素,而使用预先定义的 section.notitle.cnt 实体。
清单 4
<!ELEMENT APIdesc (APIname, (%prolog;)?, APIbody,(%info-types;)* )> <!ELEMENT APIname (%title.cnt;)*> <!ELEMENT APIbody (refsyn,usage,parameters,(%section;)*)> <!ELEMENT usage (%section.notitle.cnt;)* > <!ATTLIST usage spectitle CDATA #FIXED "Usage"> <!ELEMENT parameters ((%sthead;)?, (%strow;)+)> |
每个新元素都有到其所有祖先元素的映射。
清单 5
<!ATTLIST APIdesc
class CDATA "- topic/topic reference/reference APIdesc/APIdesc " >
<!ATTLIST APIname
class CDATA "- topic/title reference/title APIdesc/APIname " >
<!ATTLIST APIbody
class CDATA "- topic/body reference/refbody APIdesc/APIbody" >
<!ATTLIST parameters
class CDATA "- topic/simpletable reference/properties APIdesc/parameters ">
<!ATTLIST usage
class CDATA "- topic/section reference/section APIdesc/usage ">
|
注意,APIname 明确标明了在引用和主题中的等价物,虽然这里两者相同(title)。同样,用法也明确映射到引用和主题中的 section。明确的标识更便于跟踪处理复杂的映射。即使专门化层次超过 10 层,该属性仍然能够毫无歧义地映射到每个祖先信息类型。
现在已经定义了类型模块(声明了新的类型化元素及其属性)并增加了专门化属性(将新类型映射到它的祖先),可以组成一个编写 DTD 了。
清单 6
<!--Redefine the infotype entity to exclude other topic types--> <!ENTITY % info-types "APIdesc"> <!--Embed topic to get generic elements --> <!ENTITY % topic-type SYSTEM "topic.mod"> %topic-type; <!--Embed reference to get more specific elements --> <!ENTITY % reference-type SYSTEM "reference.mod"> %reference-type; <!--Embed APIdesc to get most specific elements --> <!ENTITY % APIdesc-type SYSTEM "APIdesc.mod"> %APIdesc-type; |
定义专门化类型并声明必要的属性之后,就提供了进行下列操作的基础:
- 将一般的样式表或转换应用于专门化的主题类型。
- 泛化专门化类型的主题(将其转化成更一般的主题类型)。
- 专门化一般类型的主题(将其转化成更特殊的主题类型,只有主题最初使用专门化表单编写而且经过一系列阶段后没有破坏原来的约束时才能使用)。
因为用新信息类型(如 APIdesc)编写的内容具有到原有信息类型中的等价元素或者更宽松的结构的映射(如 reference 和 topic),所以原有转换和过程可以安全地应用于新内容。默认情况下,新信息类型中的每种专门化元素被作为其一般对等物的实例。比如,APIdesc 中的 <usage> 元素将作为主题 <section> 元素处理,只不过恰好有一个固定的标签 "Usage"。
为了改变这种默认行为,作者只需要为这种元素类型创建新的、更特殊的规则然后导入默认的样式表或转换,这样不必直接编辑原来的样式表或转换就能扩展其行为。通过引用来重用降低了维护成本(每个站点只需要维护自己特殊的规则),增加了一致性(和新转换规则可以集中维护,对核心规则的维护将反映到导入这些规则的所有其他转换中)。对重用的控制从转换作者手中转移到了转换的使用者手中。
本节的其他部分假设您熟悉 XSLT,即 XSL 转换语言。
只有当一般性转换能够处理专门化元素并且专门化元素包含足够的信息让一般性转换来处理它们时,该过程才有效。
- 要求 1:映射属性 为了提供专门化信息,必须像前面那样增加专门化属性。只要在文档中包括这些属性,就可以用支持专门化的转换处理了。
- 要求 2:支持专门化的转换 转换中需要针对元素名和属性值检查匹配的模板规则。
清单 7
<xsl:template match="*[contains(@class,' topic/simpletable ']">
<!--matches any element that has a class attribute that mentions
topic/simpletable-->
<!--do something-->
</xsl:template>
|
为了修改特殊元素的一般转换,新元素类型的作者可以创建转换用于为特殊元素声明新的行为,并导入一般转换来为其他元素提供默认行为。
比如,APIdesc 专门化的转换可以对 parameters 之外的所有专门化元素进行一般处理:
清单 8
<xsl:import href="general-transform.xsl"/> <xsl:template match="*[contains(@class,' APIdesc/parameters ']"> <!--do something--> <xsl:apply-templates/> </xsl:template> |
原有的 reference properties 模板规则和新的 parameters 模板规则都与 parameters 元素匹配(因为 parameters 元素是 reference properties 元素的专门化类型,其 class 属性包含这两个值)。但是,由于 parameters 模板在导入的 样式表中,所以新模板优先。
因为专门化主题也是其祖先类型的一个实例(APIdesc 既是一种引用主题也是一种主题),所以可以安全地将一个专门化的主题转化成它的一个更一般化的祖先。如果需要将两种不同来源、分别具有不同专门化的文档组合起来,那么这种向上兼容性非常有用。祖先类型提供了两者可以转化成的公共基础。当必须要将主题提供给不支持专门化的处理过程时,这种兼容性也很有用:比如,负责每种文档类型或者使用非 DTD 感知过程的发布中心可以接收一般化的文档,从而只需要支持一种文档类型或者标记集。不过,只要可能应尽量使用支持专门化的过程和转换,这样可以避免泛化,使用更具描述性的专有形式来处理文档。
为了安全地泛化主题,需要一种方法用于从信息类型映射到目标信息类型。还需要一种办法来保留原来的类型,以便需要的时候再转换回来。
前面介绍的 class 属性可以满足这两个目的。它提供了:
- 需要映射的信息。
- 保留信息以便转换回来的方法。
每个层次的专门化都有自己的一组 class 属性,最终提供了所有专门化元素的专门化层次结构。
比如清单 9 中的 APIdesc 主题。
清单 9
<APIdesc> <APIname>AnAPI</APIname> <APIbody> <refsyn>AnAPI (parm1, parm2)</refsyn> <usage spectitle="Usage">Use AnAPI to pass parameters to your process. </usage> <parameters > ... </parameters> </APIbody> </APIdesc> |
使用公开的 class 属性(所有的值都默认由 DTD 提供):
清单 10
<APIdesc class="- topic/topic reference/reference APIdesc/APIdesc ">
<APIname class="- topic/title reference/title APIdesc/APIname ">AnAPI
</APIname>
<APIbody class="- topic/body reference/refbody APIdesc/APIbody ">
<refsyn class="- topic/section reference/refsyn ">AnAPI(parm1,
parm2)</refsyn>
<usage class="- topic/section reference/section APIdesc/usage "
spectitle="Usage">
<p class="- topic/p ">Use AnAPI to pass parameters to your process.</p>
</usage>
<parameters class="topic/simpletable reference/properties
APIdesc/parameters ">
...
</parameters>
</APIbody>
</APIdesc>
|
这里,一个模板规则可以将整个 APIdesc 主题转换成一个 reference 或者一般的主题。模板规则只需要查看 class 属性中的祖先元素名,然后重命名当前元素以与其匹配。
转换成主题后,代码类似于清单 11。
清单 11
<topic class="- topic/topic reference/reference APIdesc/APIdesc ">
<title class="- topic/title reference/title APIdesc/APIname ">AnAPI
</title>
<body class="- topic/body reference/refbody APIdesc/APIbody ">
<section class="- topic/section reference/refsyn ">AnAPI(parm1,
parm2)</section>
<section class="- topic/section reference/section APIdesc/usage "
spectitle="Usage">
<p class="- topic/p ">Use AnAPI to pass parameters to your process.</p>
</section>
<simpletable class="topic/simpletable reference/properties
APIdesc/parameters ">
...
</simpletable>
</body>
</topic>
|
即便在泛化以后,支持专门化的转换仍然可以继续将该主题看作是一个 APIdesc,因为转换可以查看 class 属性中的元素类型层次信息。
这种情况下可以通过逆反转换返回原来的形式(在 class 属性中查找专门化元素名并重新命名当前元素以与其匹配)。一旦 class 属性没有列出目标(第一个 section 没有 APIdesc 值),该元素就被改编成列出的最后一个值(因此第一个 section 实际上变成了 refsyn)。
但是,如果在一般化的 topic 中改变了内容结构(比如改变了 section 的顺序),结果可能对专门化信息类型不再有效(对于 APIdesc 来说,APIbody 中的信息有一定的顺序)。因此虽然映射到更一般化的类型是安全的,但是再映射回专门化类型时可能会出现问题:专门化类型有更多的规则使得内容专门化。但是内容处于更一般的形式时并不保证这些规则。
如果内容最初是用专门化类型编写的,专门化一个一般性的主题比较简单。但是,如果在一般化层次上编写了内容而又希望设置更具体的类型,情况则比较复杂。
比如,假设创建了一些引用主题。然后分析其内容后发现具有统一的模式。现在希望保持这种范式,并将其用专门化的信息类型(比如 API 描述)来描述。要进行专门化,首先要创建目标 DTD,然后在内容中增加足够的信息以便进行迁移。
专门化信息可以放在两个地方:
- 添加到
class属性中。必须小心保持顺序的正确性并包括所有的祖先类型值。 - 在
outputclass属性中给出目标元素名,根据这个值迁移,然后增加class属性值。
无论哪种情况,迁移之前都要运行验证性转换查找适当的属性,然后检查该元素内容在专门化的内容模型中是否有效。可以使用 Schematron 这样的工具生成验证转换和迁移转换,也可首先完成迁移然后使用专门化的 DTD 验证迁移是否成功。
与 XML DTD 语法类似,XML Schema 语言也是一种定义词汇表(元素和属性)和词汇表约束(如内容模型或者固定值与隐含值)的方式。它具有内置的专门化机制,包括限制许可的专门化的能力。使用 XML Schema 语言代替 DTD 更容易对专门化信息类型表示一般类型的有效子集进行检查,可以通过泛化和发布转换保证平滑处理。
与 DTD 不同,XML 模式用 XML 文档表示。因此可以用 DTD 无法使用的方式处理。比如可以维护一种 XML 模式然后使用 XSL 生成两个版本:
- 消除了固定属性和改写元素的编写版本。
- 包括从转化和发布转换派生而来的 class 属性的共处理程序使用的版本
但是,XML 模式还不是很流行,不能够全部采用。主要问题是缺乏编写工具和标准发展中实现的不兼容性。随着标准的完成和模式得到更广泛的采用与支持,今后一两年内业界将解决这些问题。
可以使用下面的一般过程创建专门化信息类型:
- 确定需要的元素。
- 确定到一般类型元素的映射。
- 检查专门化元素的内容模型是否比一般元素的限制更多。
- 创建类型模块文件包含专门化元素和属性声明(包括
class属性)。 - 创建编写的 DTD 文件,用于导入适当的类型模块。
可以使用下面的一般过程创建专用的 XSL 转换:
- 为信息类型创建新的转换。
- 导入希望扩展的已有转换。
- 确定需要专门处理的元素。
- 增加和这些元素按照
class属性内容匹配的模板规则。
虽然可以为一般 DTD 中的任何标记创建新的等价元素,但是除非内容模型包含也进行专门化的标记,否则这对作者来说毫无用处。在 APIdesc 的例子中,parameters 元素在 topic 或 reference 中的任何地方都是无效的内容。为了使用它,必须为参数创建有效的上下文,惟一的办法就是创建主题级的容器。为了向作者公开 parameters 元素,需要对下列部分进行专门化:
body元素,允许把参数作为有效内容(得到了APIbody)。topic元素,允许专门化 body(得到了APIdesc)。
可以使用领域专门化来避免这种多米诺骨牌效应。如果只希望为已有的信息类型增加一些新的可变结构,应使用领域专门化而不是主题专门化(请参阅 参考资料 中的 “Specializing domains in DITA”)。
为了保证专门化元素和对应的一般元素相比有更多的约束(就是说其值是一般元素所允许结构的真子集),需要查看一般元素的内容模型。可以按照表 4 安全地改变专门化元素的内容模型:
表 4. 专门化规则一览表
| 内容类型 | 允许的专门化 | 例子(从一般到特殊) |
| 必需的 | 只需要重命名 |
<!ELEMENT General(a)> <!ELEMENT Special(a.1)> |
| 可选(?) | 重命名,改为必需的或者删除 |
<!ELEMENT General(a?)> <!ELEMENT Special(a.1?)> <!ELEMENT Special(a.1)> <!ELEMENT Special EMPTY> |
| 一个或多个(+) | 重命名,改为必需的,分解成必需元素加上其他元素,分解成一个或更多元素再加上其他元素。 |
<!ELEMENT General(a+)> <!ELEMENT Special(a.1+)> <!ELEMENT Special(a.1)> <!ELEMENT Special(a.1,a.2,a.3+,a.4*)> <!ELEMENT Special(a.1+,a.2,a.3*)> |
| 零个或多个(*) | 重命名,改为必需的、可选的,分解成必需元素加其他元素,分解成可选元素加其他元素,分解成一个或多个元素加其他其他,分解成零个或多个元素加其他元素,删除 |
<!ELEMENT General(a*)> <!ELEMENT Special(a.1*)> <!ELEMENT Special(a.1)> <!ELEMENT Special(a.1?)> <!ELEMENT Special(a.1,a.2,a.3+,a.4*)> <!ELEMENT Special(a.1?,a.2,a.3+,a.4*)> <!ELEMENT Special(a.1+,a.2,a.3*)> <!ELEMENT Special(a.1*,a.2?,a.3*)> <!ELEMENT Special EMPTY> |
| 多选一 | 重命名或者选择一个 |
<!ELEMENT General (a|b)> <!ELEMENT Special (a.1|b.1)> <!ELEMENT Special (a.1)> |
假设有一个一般化的元素 General,内容模型为 (a,b?,(c|d+))。此定义表示,General 必须包含元素 a,后面可以跟元素 b,最后必须是 c 或者一个/多个 d。
清单 A. 一般元素 General 的内容模型
<!ELEMENT General (a,b?,(c|d+))> |
如果对 General 专门化创建 Special 元素,其内容模型必须具有同样或更多的限制:允许出现的内容不能比 General 多,否则就不能向上映射或者保证泛化过程、转换或样式表的正确行为。
先不用管重命名(重命名总是可以的,它仅仅意味着专门化 Special 可以包含的某些元素),下面是可用于 Special 内容模型的一些合法修改,得到的是具有相同或更多限制的内容规则:
清单 B. 对模型 Special 的合法修改,使 b 成为必需的
<!ELEMENT Special (a,b,(c|d))> |
Special 现在要求 b 必须出现,而不再是可选的,并且只允许一个 d。它可以安全地映射到 General。
清单 C. 对模型 Special 的合法修改,使 c 成为必需的而禁止 d
<!ELEMENT Special (a,b?,c)> |
Special 现在要求 c 必须出现,而且不允许 d。它可以安全地映射到 General。
清单 D. 对模型 Special 的合法修改,对必需的 d 进行三种专门化
<!ELEMENT Special (a,b?,d1,d2,d3)> |
Special 现在要求出现 d 的三种专门化,不允许出现 c。它可以安全地映射到 General。
每个元素必须有一个 class 属性。class 属性以空白开始和结束,包含一系列空白分隔的值。每个值有两个部分:第一部分是主题类型,第二部分(/之后)是元素类型。class 属性值应该在 DTD 中被声明为默认属性值。一般来说作者不应该修改这些值。
例子:
<appstep class="- topic/li task:step bctask/appstep ">A specialized
step</appstep>
|
专门化类型声明新的元素时,必须提供新元素的 class 属性。class 属性必须包含到专门化类型谱系中每种主题类型的映射,即使没有出现元素重命名也应如此。映射应该从主题开始,到当前元素类型结束。
例子:
<appname class="- topic/kwd task/kwd bctask/appname "> |
为了保证泛化和专门化转换能够简单而准确地映射值这是必需的。比方说,假设省略了值 task/kwd,当需要将 bctask 映射到任务主题时,转换就必须猜测映射到 kwd(如果 task 更一般的话,这里就是这种情况)还是保留 appname(如果 task 比较具体的话,这里不是这种情况)。因为总是提供到更一般的值的映射,所以我们可以采用一条简单的规则,即省略的映射必须默认为更具体的值,就是说采用列表中的最后一个值。虽然这个例子很简单,但是在更复杂的层次中(比方说有五层,第二层和第四层发生了重命名),这种映射非常重要。
专门化类型不一定要改变未专门化元素的 class 属性,值需要通过引用更一般的层级重用。比如,因为 task 和 bctask 未经专门化而直接使用 p 元素,不需要为其声明映射。
专门化类型只需要为专有的元素声明 class 属性。也不需要为其重用或继承的元素声明 class 属性。
根据 class 属性值设计 XSLT 模板可以让转换应用于整个元素类型分支而不仅仅是单个元素类型。
在检查元素名的任何地方(任何包含元素名值的 XPath 语句)都需要改为检查元素的 class 属性的内容。即使无法识别元素,class 属性也可以让转换知道该元素属于某种已知的元素,并根据其规则安全地处理。
例子:
<xsl:template match="*[contains(@class,' topic/li ')]"> |
该匹配语句可用于遇到的任何 li 元素。它可用于 step 和 appstep 元素,即使不知道它们的具体类型,因为 class 属性告诉了模板它们的一般类型。
<xsl:template match="*[contains(@class,' task/step ')]"> |
该匹配语句不能用于一般的 li 元素,但是可用于 step 和 appstep 元素,虽然不知道 appstep 是什么,但知道将其作为 step 来处理。
一定要在 class 属性字符串检查中包含前导和尾部空格。否则可能造成匹配失败(没有空格的话 task/step 可以匹配 notatask/stepaway,显然不希望这种情况)。
创建领域专门化时,新元素仍然需要 class 属性,但是应该以 “+” 而不是 “-” 开始。这样就告诉泛化转换以不同的方式处理元素:支持领域的泛化转换可能以不同的逻辑处理领域和主题专门化。
领域专门化应该从主题(根 topic 类型)或者其他领域专门化派生而来。不要通过专门化已经专门化的主题类型来创建领域,这样可能造成意料之外的泛化行为,该体系结构目前还不支持。
本文中提供的信息没有经过任何正式的 IBM 测试,仅供参考,不作任何明确或隐含的保证。使用这些信息或者文中所述这些技术的实现是读者的责任,依赖于读者评价和将其结合到操作环境中的能力。尝试根据自己的环境改变这些技术的后果自负。
? Copyright International Business Machines Corp., 2002.版权所有。
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
-
2004 年 3 月,IBM 将 DITA 捐赠给了 OASIS 标准化组织,现在由 OASIS DITA 技术委员会管理(http://www.oasis-open.org/committees/dita/)。2005 年 4 月 OASIS 批准了 DITA 规范的 1.0 版本,包括下列文档:
- OASIS Darwin Information Typing Architecture (DITA) Language Specification:http://xml.coverpages.org/DITAv10-OS-LangSpec20050509.pdf
- OASIS Darwin Information Typing Architecture (DITA) Architectural Specification:http://xml.coverpages.org/DITAv10-OS-ArchSpec20050509.pdf
- 可以从 OASIS DITA 技术委员会网站的文档部分下载一个 .zip 文件,其中包含所有规范、DTD 和 Schema:http://www.oasis-open.org/committees/download.php/12091/cd2.zip
适用于 DITA DTD/Schema developerWorks 和 OASIS 1.0 版本的参考实现工具箱可从 SourceForge 的 DITA Open Toolkit 项目网站下载:http://dita-ot.sourceforge.net。DITA Open Toolkit 代替了 developerWorks 以前发布的所有版本,最新版本通常称为 “dita132”。
- 请阅读 Darwin 信息类型化体系结构简介(developerWorks,2005 年 9 月修订)。
- 阅读 Erik Hennum 的文章 DITA 中对域进行专门化,该文介绍了如何利用可扩展的 DITA DTD 描述新的信息领域(developerWorks,2005 年 9 月)。
- 看看如何参与 Don Day 和 Michael Preistley 主持的 DITA 论坛。
- 直接访问 Don Day 和 Michael Preistley 主持的 DITA 论坛。
-
下载 最新的 DITA DTD、样式表和示例文档。
- 如果需要了解 XSLT,请阅读 Michael Kay 的技术文章 “What kind of language is XSLT?”(developerWorks,2005 年 4 月)。
Michael Priestley 是 IBM Toronto Software Development Laboratory 的一位信息开发人员。他撰写了关于超文本导航、信息资源单一化、动态文档接口等方面的一些文章。他目前从事帮助和文档管理的 XML 和 XSL 开发。可以通过 mpriestl@ca.ibm.com 与 Michael 联系。