使用 XSLT 2.0 为内容添加结构和语义

将非结构化的叙述性内容转换为结构化的、具有丰富特性的 XML

当您将现有内容转换为电子书格式、DITA 或其他结构化标准时,常常需要推断结构并将该结构添加到您的文档中。XSLT 2.0 的高级正则表达式和分组功能使其成为用于转换和增强内容的一门优秀语言。当您将非结构化或半结构化叙述性内容转换为更好地结构化的词汇并查看几个常见场景时,就会发现一些最有用的 XSLT 2.0 特性。

Priscilla Walmsley, 常务董事, Datypic

Priscilla Walmsley 的照片Priscilla Walmsley 是 Datypic 公司的常务董事和高级顾问。她擅长 XML 技术、架构和实现。最近,她一直忙于通过 Trusted Federal Systems 公司和美国司法部一起开发 LEXS —— 一个基于 NIEM 的 IEPD 框架。她是 Definitive XML Schema(Prentice Hall,2001)和 XQuery(O'Reilly Media,2007)的作者,还是 Web Service Contract Design and Versioning for SOA(Prentice Hall,2008)的合著者。



2011 年 8 月 23 日

过去,叙述性内容进行了标记,用于表示内容的外观(例如,字体大小或文本对齐方式),而不是其真实的结构或含义。这种方法非常适用于图书印刷、办公文档以及许多 Web 页面的内容。一些叙述性内容根本没有进行标记,而是以纯文本段落形式呈现。

常用缩略语

  • CSS:级联样式表
  • DITA:达尔文信息类型体系结构
  • HTML:超文本标记语言
  • XHTML:可扩展 HTML
  • XML:可扩展标记语言
  • XSLT:可扩展样式表语言转换

随着内容管理、电子发布、高级搜索和查询技术的出现,内容所有者现在已认识到结构化信息的威力,并使用相应的方式来标记他们的新内容。但是,许多人仍然存留有旧的内容,这些内容是非结构化或半结构化的,或只为了演示目的而进行标记。

为了令现有内容更具可读性,可为其添加结构,从而使您能够:

  • 分别对多个输出设备(如智能手机、电子书阅读器和替代 Web 浏览器)的内容进行样式化
  • 实现与某些种类的文本(比如文档内部或文档之间的引用中的超链接,或用于地址的弹出指示)有关的交互式行为
  • 生成内容的替代表示,如内容表、索引和摘要视图
  • 根据内容中的字段提供更受专注的搜索
  • 确保整个内容正文具有更一致的格式
  • 改进对内容的检验,例如,确定某个法律文档中的文档内部引用是否有效

使用 XSLT 2.0

XSLT 2.0 是一种适应性很强的技术,可用于为叙述性内容添加结构。人们越来越多地使用 XML 或易于转化为 XML 的格式(如 HTML)来表示叙述性内容。与其他一些用于处理文本的流行脚本语言不同的是,XSLT 完全支持 XML。它理解 XML 语法、编码和名称空间的许多变体。

XSLT 同样适用于叙述性内容,因为它提供了很好的灵活性。使用模板规则处理输入文档中的各种事件意味着会话可以是由内容驱动的,而不是严格按照顺序控制。

与专注于 XML 样式化的 XSLT 1.0 不同,XSLT 2.0 提供了一些用于转换内容的高级功能,这些功能可以实现以下操作:

  • 通过正则表达式来确定文本中的模式
  • 按照值或位置对元素进行分组
  • 一个样式表一个文档地多次传递文档
  • 将一个文档分割成多个文档,或将多个文档组合成一个文档

要使用 XSLT,第一步是将内容转换为 XML 形式。大多数文档编辑器和其他内容工具都有 XML 导出功能。根据所使用的工具,XML 很可能非常复杂,因此第一步是将 XML 转换为一种简便形式,以便更容易处理它。

如果是从 HTML 进行转换,HTML Tidy(参见 参考资料 中的链接)会将您的 HTML 转换为 XHTML,可以将 XHTML 作为 XSLT 的输入,因为它是一种格式良好的 XML。它还简化了您的文档。


技巧

本文其余部分将介绍使用 XSLT 2.0 为内容添加结构和语义的技巧,并且特别关注作为输入文档的 XHTML 和 Microsoft® Office Word XML,但这些概念适用于任何叙述性输入文档。

您可以在本节中以可下载的 ZIP 文件(参见 下载)的形式下载所有示例。对于 XSLT 2.0 处理,我建议使用 Saxon(参见 参考资料 中的链接)。

识别文本模式

识别文本中的特定模式并进行标记通常十分有用。URL、电子邮件地址、电话号码、文档间引用以及 wiki 类型的格式化都遵循通用的模式,可以通过正则表达式识别它们。

清单 1 显示了一个输入文档,该文档包含纯文本形式的电子邮件地址。假设您希望使用 a(锚)元素标记每个电子邮件地址,从而实现电子邮件地址的链接,该链接采用 HTML 表示,允许用户通过单击地址来向其发送电子邮件。

清单 1. 文本模式识别 XSLT 的样例输入
<document>
  <p>Priscilla Walmsley can be reached at pwalmsley@datypic.com.</p>
  <p>Questions about XSLT in general are best asked on the XSL list at
    xsl-list@lists.mulberrytech.com (subscription required.) </p>
</document>

清单 2 中的 XSLT 实现了这个目标。它使用 XSLT 2.0 analyze-string 指令对字符串进行测试,看它是否与某个正则表达式匹配。analyze-string 指令有两个子元素:matching-substring 表示如何处理匹配模式的子字符串,而 non-matching-substring 则表示如何处理其余的文本。

在本例中,第一个模板规则匹配输入文档中的每个文本节点。当它发现匹配 regex 属性中指定的正则表达式的文本后,它将插入一个 a 元素。该元素提供了一个 href 属性,将字符串 mailto: 与电子邮件地址连接起来。它还将电子邮件地址放入 a 元素的内容中。在 matching-substring 指令内部,句号(.)表示匹配模式的字符串。

如果全部或部分文本节点与模式不匹配,则仅执行复制操作,如 non-matching-substring 中定义的那样。XSLT 中的第二个模板规则会命令处理器复制所有元素并继续执行子元素,因此,除了电子邮件地址外,其他内容没有发生改变。

清单 2. 文本模式识别 XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="text()">
  <xsl:analyze-string select="."
                      regex="[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{{2,4}}">
    <xsl:matching-substring>
      <a href="mailto:{.}">
        <xsl:value-of select="."/>
      </a>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:copy/>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:template>

<xsl:template match="*">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

清单 3 显示 XSLT 的输出,其中电子邮件地址标记为 a 元素。

清单 3. 文本模式识别 XSLT 的样例输出
<document>
 <p>Priscilla Walmsley can be reached at
   <a href="mailto:pwalmsley@datypic.com">pwalmsley@datypic.com</a>.</p>
 <p>Questions about XSLT in general are best asked on the XSL list at
   <a href="mailto:xsl-list@lists.mulberrytech.com">xsl-list@lists.mulberrytech.com</a>
   (subscription required.) </p>
</document>

添加结构容器

在较高的层面上,添加表示文档分支或小节的结构通常很有用。您可以添加结构以遵循某种特定的 XML 词汇表,比如 DocBook。或者您可能希望清晰地描述部分内容,从而可以使用 DITA 之类的技术重新构建内容。

例如,清单 4 展示了一个采用扁平结构的 XHTML 输入文档。小节标题(h1h2)出现在与段落相同的级别,并且未使用结构标记对小节进行分组。

清单 4. 节分组 XSLT 的样例输入
<html>
 <h1>Chapter 1</h1>
 <h2>Section 1.1</h2>
 <p>In this section...</p>
 <p>More text</p>
 <h2>Section 1.2</h2>
 <p>In this second section...</p>
</html>

清单 5 中的 XSLT 使用 XSLT 2.0 的分组功能根据小节标题的位置添加 section 元素。它创建了两个级别的组。首先,它使用一个 for-each-group 指令,该指令使用 group-starting-with="h1" 属性对 html 的所有子元素进行分组。该方法意味着 h1 元素表示某个组在这个级别的开始部分。XSLT 会为这些组中的每一个组插入一个 section level="1" 元素。

其次,它包含一个内部 for-each-group,后者调用 current-group 函数获取 h1 组中的所有项,并使用它们创建子组。子组的开始部分由 h2 元素定义。

在内部 for-each-group 中,它将使用 XPath current-group()[self::h2] 测试组是否包含 h2 元素。这样做是因为要创建一个组,其中的所有内容均位于第一个 h2 元素之前,在本例中,该元素是 h1 元素。您可能并不希望其他 section level="2" 围绕该元素。

清单 5. 对 XSLT 中的节进行分组
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="html">
  <document>
    <xsl:for-each-group select="*" group-starting-with="h1">
      <section level="1">
        <xsl:for-each-group select="current-group()" group-starting-with="h2">
          <xsl:choose>
            <xsl:when test="current-group()[self::h2]">
              <section level="2">
                <xsl:apply-templates select="current-group()"/>
              </section>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </section>
    </xsl:for-each-group>
  </document>
</xsl:template>

<xsl:template match="h1|h2">
  <heading>
    <xsl:apply-templates/>
  </heading>
</xsl:template>

<xsl:template match="node()">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

清单 6 展示了 XSLT 的输出,其中包含两级 section 元素。

清单 6. 节分组 XSLT 的样例输出
<document>
   <section level="1">
      <heading>Chapter 1</heading>
      <section level="2">
         <heading>Section 1.1</heading>
         <p>In this section...</p>
         <p>More text</p>
      </section>
      <section level="2">
         <heading>Section 1.2</heading>
         <p>In this second section...</p>
      </section>
   </section>
</document>

分组不是基于起始元素,相反,有时需要对彼此相邻的项进行分组。列表项就是这样一个例子,其表现形式就是一些相邻的普通段落,而非列表中分组到一起的内容。因此,for-each-group 指令可以使用 group-adjacent 属性代替 group-starting-with

从节号推测结构

有时,您希望同时进行分组并推测结构。与之前的示例不同,清单 7 中的输入文档的所有文本都被标记为通用段落。辨别结构的唯一方法是对内容进行测试以获得相应模式。

清单 7. 节推测 XSLT 的样例输入
<document>
 <p>Chapter 1: In the beginning</p>
 <p>In this chapter...</p>
 <p>1.1 Introduction</p>
 <p>In this section...</p>
 <p>More text</p>
 <p>1.2 Next Steps</p>
 <p>In this second section...</p>
</document>

实现这一目标的最简便方法就是使用 XSLT。清单 8 中的 XSLT 对文档遍历了两次,并使用模式区分这两次遍历功能。

清单 8. 节推测 XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="chapRegex" select="'^\s*Chapter\s+(\d+)\s*:\s*(.*)$'"/>
<xsl:variable name="secRegex" select="'^\s*(\d+\.\d+)\s*(.*)$'"/>

<xsl:template match="document">
  <xsl:variable name="renamed" as="element()*">
    <xsl:apply-templates select="*" mode="rename"/>
  </xsl:variable>
  <document>
    <xsl:for-each-group select="$renamed" group-starting-with="chapTitle">
      <chapter num="{replace(current-group()[self::chapTitle],$chapRegex,'$1')}">
        <xsl:for-each-group select="current-group()" group-starting-with="secTitle">
          <xsl:choose>
            <xsl:when test="current-group()[self::secTitle]">
              <section num="{replace(current-group()[self::secTitle],$secRegex,'$1')}">
                <xsl:apply-templates select="current-group()"/>
              </section>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </chapter>
    </xsl:for-each-group>
  </document>
</xsl:template>

<xsl:template match="p[matches(.,$chapRegex)]" mode="rename">
  <chapTitle>
	 <xsl:copy-of select="node()"/>
  </chapTitle>
</xsl:template>

<xsl:template match="p[matches(.,$secRegex)]" mode="rename">
  <secTitle>
	 <xsl:copy-of select="node()"/>
  </secTitle>
</xsl:template>

<xsl:template match="text()" priority="1">
  <xsl:choose>
    <xsl:when test="matches(.,$chapRegex) and (. is parent::chapTitle/node()[1])">
      <xsl:value-of select="replace(.,$chapRegex,'$2')"/>
    </xsl:when>
    <xsl:when test="matches(.,$secRegex) and (. is parent::secTitle/node()[1])">
      <xsl:value-of select="replace(.,$secRegex,'$2')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="."/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="node()" mode="#all">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates mode="#current"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

第一次遍历将确定哪些 p 元素真正用于表示章标题和节标题,并对它们重新命名,以简化稍后进行的分组遍历。这里创建了一个 $renamed 变量,用来包含第一次遍历的结果。在其定义中,对模板应用了 rename 模式。rename 模式中的两个模板规则将查找表示章或节标题的段落,并重命名它们。为了确定这些段落,将使用 matches 函数(XSLT 2.0 中的新增内容),以确定某个字符串是否匹配正则表达式。在本例中,正则表达式使用变量 $chapRegex$secRegex 表示。

清单 9 显示了第一次遍历后的 $renamed 变量,但是它没有直接显示在结果中。

清单 9. 节推测 XSLT 中的 $renamed 变量值
<document>
 <chapTitle>Chapter 1: In the beginning</chapTitle>
 <p>In this chapter...</p>
 <secTitle>1.1 Introduction</secTitle>
 <p>In this section...</p>
 <p>More text</p>
 <secTitle>1.2 Next Steps</secTitle>
 <p>In this second section...</p>
</document>

第二次遍历以 for-each-group 指令开头,它的 select 属性表示它将处理 $renamed 变量而不是输入文档。第二次遍历使用与前一个例子十分类似的分组逻辑创建了一个两层结构:chaptersection

它还创建了包含章号和节号的 num 属性。为此,它使用了 XSLT 2.0 中的另一个新函数 replacereplace 函数采用了三个参数:第一个参数是要修改的文本,第二个参数是与将要替换的部分匹配的正则表达式,第三个参数是替换字符串。在本例中,第三个参数利用了子表达式,其中 $2 表示它应当包括匹配正则表达式中第二个圆括号的文本。

text() 模板规则从内容中删除了章号和节号,因为可以将它们移至 num 属性。该属性也使用 replace 函数。您需要注意的是,不要通过替换每个与模式相匹配的文本节点来测试它是否是该父元素中的第一个文本节点。

node() 模板规则复制所有不具备更具体模板的元素。使用 mode="#all" 意味着不管您是应用 rename 模式还是没有应用任何模式,都将使用该模板。当按照该模板规则应用模板时,会使用 mode="#current" 表示您应当首先处于匹配模板的模式下。

尽管模式的使用在 XSLT 2.0 中并不新鲜,但是 #all#current 关键字的应用是新出现的,同样,对文档执行多次遍历的功能也是新增的。由于结果树片段存在一些限制,所以这些功能无法在 XSLT 1.0 中实现。

清单 10 展示了最终输出。

清单 10. 节推测 XSLT 的样例输出
<document>
   <chapter num="1">
      <chapTitle>In the beginning</chapTitle>
      <p>In this chapter...</p>
      <section num="1.1">
         <secTitle>Introduction</secTitle>
         <p>In this section...</p>
         <p>More text</p>
      </section>
      <section num="1.2">
         <secTitle>Next Steps</secTitle>
         <p>In this second section...</p>
      </section>
   </chapter>
</document>

使用样式信息

指定样式对于判断文档的真正结构非常重要。尽管指定样式通常意味着指定格式并使其标准化,但也可以用它表示内容的结构和含义。在许多技术中,结构和样式是两种不同的事务。例如,在 Microsoft Office Word 中,文本被组织成段落,而样式则应用于这些段落或这些段落中的文本。在 HTML 中,结构化元素可能存在不同的变体,如 h1p,但是它们都将通过 class 属性来应用 “样式”,class 属性引用了 CSS 样式表。

图 1 展示了应用了样式的 Word 文档,其中标题 1 和标题 2 段落样式用于节标题,而 Emphasis 和 Strong 等字符样式应用于内部的文本格式。

图 1. 使用了样式的 Word 文档
使用了段落和内部文本样式的 Word 文档示例

在通过 XSLT 运行该文档之前,我将该文档保存为 Word XML。这里并没有提供 Word XML 文件,因为该文件体积庞大且十分复杂,但可以通过下载获得它(参见 下载)。

我建议创建一个样式映射文档,清单 11 显示了该文档的一个例子。它将输入文档中的样式映射到结果中的对应的结构元素。这种映射使转换变得更加通用和灵活,并且更加易于维护。

清单 11. Word 转换 XSLT 中的样式映射
<styles>
  <style>
    <name>BodyText</name>
    <name>Normal</name>
    <transformTo>p</transformTo>
  </style>
  <style>
    <name>ListParagraph</name>
    <transformTo>li</transformTo>
  </style>
  <style>
    <name>Heading1</name>
    <transformTo>h1</transformTo>
  </style>
  <style>
    <name>Heading2</name>
    <transformTo>h2</transformTo>
  </style>
  <style>
    <name>Emphasis</name>
    <transformTo>em</transformTo>
  </style>
  <style>
    <name>Strong</name>
    <transformTo>strong</transformTo>
  </style>
</styles>

清单 12 中的 XSLT 将 Word XML 文档转化为 XML,并创建了样式映射中指定的元素。它必须为以下两个元素定义模板规则:w:p (段落)和 w:r (文本运行)。对于这两个元素中的每一个,它都将确定相关的样式,并在样式映射中查找该样式。随后,它会使用 xsl:element 创建一个 XML 元素,其名称可以在样式映射的 transformTo 中找到。

清单 12. 将 Word 样式转化为 XML 标记
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
        exclude-result-prefixes="w">
<xsl:variable name="styles" select="doc('stylemap.xml')/styles/style"/>

<xsl:template match="/">
  <document>
    <xsl:apply-templates select=".//w:p"/>
  </document>
</xsl:template>

<xsl:template match="w:p">
  <xsl:variable name="elName"
                select="$styles[name=current()/w:pPr/w:pStyle/@w:val]/transformTo"/>
  <xsl:choose>
    <xsl:when test="$elName != ''">
      <xsl:element name="{$elName}">
       <xsl:apply-templates select="*"/>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <!-- paragraphs without a listed style are just plain p's -->
      <p>
        <xsl:apply-templates select="*"/>
      </p>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="w:r">
  <xsl:variable name="elName"
                select="$styles[name=current()/w:rPr/w:rStyle/@w:val]/transformTo"/>
  <xsl:choose>
    <xsl:when test="$elName != ''">
      <xsl:element name="{$elName}">
        <xsl:apply-templates select="*"/>
      </xsl:element>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="*"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

清单 13 展示了样例输出。在本例中,我并没有实际添加或推测某些新的信息,而是将结构和样式组合到一组标记中。执行到这一步骤时,您可以应用本文所述的其他技巧来添加结构并识别文本模式。

清单 13. Word 样式转换 XSLT 的样例输出
<document>
   <h1>Chapter 1: In the beginning</h1>
   <p>In this chapter...</p>
   <h2>1.1 Introduction</h2>
   <p>In this section there is a list.</p>
   <li>item 1</li>
   <li>item 2</li>
   <li>item 3</li>
   <h2>1.2 Next Steps</h2>
   <p>This section uses character styles
         <strong>Strong</strong> and <em>Emphasis</em>.</p>
</document>

尽管该示例使用的是 Word,但您也可以对 XHTML 执行类似的转换,使用 class 属性判断样式。本文在 ZIP 下载文件中提供了有关这种转换的示例(参见 下载)。

使用格式化信息

在某些情形下,指定样式信息是不可用的。对于 Word,不同用户可能使用不同的技术创建输入文档,包括直接应用字体更改而不是使用样式。类似地,在 HTML 中,作者或编写工具可能会对段落和其他元素应用不同的样式属性,而不是定义可以重用的 CSS 类。在这类情况下,要推测结构,则必须依靠文本格式化,比如字体大小和字体效果(如粗体和斜体)。这种做法在可靠性和一致性方面要逊色于样式,但是仍然可以提供重要的线索。

图 2 显示了一个使用直接格式化而非样式的 Word 文档。该文档的作者没有使用样式,而是对所有内容都采用 Normal 样式,直接修改字体大小,然后应用粗体和斜体使某些段落看上去类似于标题。

图 2. 使用格式化而非样式的 Word 文档
使用直接格式化的 Word 文档示例

清单 14 中的 XSLT 根据 Word 文档的格式化信息而非样式名称将该文档转换为 XML 格式。它测试了字体的大小以及是否应用了粗体和斜体效果,从而判断标题是一级标题还是二级标题。在这种类型的转换中,样式映射就不是那么有用了,因为映射规则更加复杂,并且最适合使用 XSLT 和 XPath 代码表示。

清单 14. 从 XSLT 中的文本格式获得有关结构的提示
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
        exclude-result-prefixes="w">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
  <document>
    <xsl:apply-templates select=".//w:p"/>
  </document>
</xsl:template>

<xsl:template match="w:p">
  <xsl:variable name="size" select="w:pPr/w:rPr/w:sz/@w:val"/>
  <xsl:choose>
    <xsl:when test="($size > 32) and exists(w:pPr/w:rPr/w:b)">
      <h1>
        <xsl:apply-templates select="*"/>
      </h1>
    </xsl:when>
    <xsl:when test="($size > 25) and exists(w:pPr/w:rPr/w:i)">
      <h2>
        <xsl:apply-templates select="*"/>
      </h2>
    </xsl:when>
    <xsl:otherwise>
      <p>
        <xsl:apply-templates select="*" mode="char-formatting"/>
      </p>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="w:r" mode="char-formatting">
  <xsl:choose>
    <xsl:when test="w:rPr/w:b">
      <b>
        <xsl:apply-templates select="*"/>
      </b>
    </xsl:when>
    <xsl:when test="w:rPr/w:i">
      <i>
        <xsl:apply-templates select="*"/>
      </i>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates select="*"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

清单 15 展示了样例输出。

清单 15. Word 格式化 XSLT 的样例输出
<document>
   <h1>Chapter 1: In the beginning</h1>
   <p>In this chapter...</p>
   <h2>1.1 Introduction</h2>
   <p>In this section...</p>
   <h2>1.2 Next Steps</h2>
   <p>In this section there is text that uses <b>bold</b>
     and <i>italics</i>.</p>
</document>

XHTML 中的一个类似应用就是使用 style 属性或格式化元素,如 fontcenter


注意事项和结束语

本文给出的所有示例都非常简单,主要用于培训目的。实际使用中遇到的内容可能要更加复杂。在某些场景下,可能会遇到非常一致的输入文档,例如,您将转换由生产编辑器认真纠正过的 Word 文档,或者由某个应用程序通过一致的方式生成的 XHTML 文档。

但通常情况下,内容都是杂乱无章的。如果内容是手工生成的,那么很可能存在许多变化。当您创建自己的 XSLT 时,不应当存有生成一致文档的侥幸。您需要频繁地对代码进行测试,编写捕捉未处理情形的模板并发出警告消息。

您应该特别关注混合内容。如果要转换包含混合内容的文档,一定要使用 apply-templates 而不是 value-of,后者会不小心使混合内容变单调。

在处理叙述性内容时,空白区域也非常重要。避免在 XSLT 中对输出使用缩进,因为这可能会引入一些不希望看到的空白区。相反,避免从输入文档中删除空白,因为它们可能是有意放在那里的。

始终建议对您的输出进行检查。尽管检查大量的内容十分耗时,但是至少应该对输出进行抽查以找出重复错误。


下载

描述名字大小
本文的样例 XSLT 样式表examples.zip21KB

参考资料

学习

获得产品和技术

  • Saxon:下载用于测试本文示例的XSLT 2.0 处理器。
  • HTML Tidy:下载可将 HTML 转化为格式良好的 XML 的开源解析器。
  • IBM 产品评估试用版软件:下载或 IBM SOA 人员沙箱,并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=753527
ArticleTitle=使用 XSLT 2.0 为内容添加结构和语义
publish-date=08232011