xslt生成序号
在具有逻辑部分的长网页中,一种良好的可用性模式是在顶部提供一个链接索引,以链接到文档的各个子部分,从而使浏览器后面的人员可以轻松地快速访问所需的内容。 这些可以很容易地用HTML表示。 该点标记有一个命名锚点:
<a name="section3"&>
链接使用引用锚名称的片段:
<a href="#section3"&>
XSLT提供了许多生成此类链接的途径,并且本技巧文章介绍了在各种情况下处理此任务的两种技术。
使用方便的字符数据
一种方法是在数据中使用字符数据字段:属性或元素内容。 假设DocBook词汇表中有一个文档。 只是为了好玩,对于清单1,我对英国戏剧的时期进行了愚蠢的总结。 在这里节省空间是故意简短的,但是如果您认为每个部分实际上都会继续进行而不是一段简短的内容,那么您应该了解一下。
<?xml version='1.0'?>
<article>
<sect1>
<title>Elizabethan</title>
<para>Shakespeare his histories, Jonson his charlatans.</para>
</sect1>
<sect1>
<title>Jacobean</title>
<para>"Webster was much possessed by death..."</para>
</sect1>
<sect1>
<title>Georgian</title>
<para>
Shaw the sly subversive. Fabian and common sense storyteller.
</para>
</sect1>
</article>
顶级部分( sect1
元素)将是分割文档的理想点(假设您想要这样做,因为该文档在每个部分中都有更典型的文本量)。 您可以使用清单2中的转换将其转换为HTML,该转换用带字母的注释标记,其中的细节需要进一步说明。
<?xml version="1.0"?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:template match="/">
<html>
<head/>
<body>
<h2>Contents</h2>
<!-- A -->
<xsl:apply-templates mode="toc"/>
<hr/>
<!-- B -->
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<!-- C -->
<xsl:template match="sect1" mode="toc">
<a href="#{title}"><xsl:value-of select="title"/></a><br/>
</xsl:template>
<!-- D -->
<xsl:template match="sect1">
<div>
<h2><a name="{title}"><xsl:value-of select="title"/></a></h2>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="title"/>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:transform>
清单2的A部分
首先,生成内容链接列表。 XSLT模式对此非常理想。 有一组特殊的模板(或者实际上是单个模板)来处理生成内容链接的特殊模式,称为toc
。 该行调用该模式。 article
元素没有匹配的模板,因此它遵循默认模板并将模板应用于其子元素,从而保持模式。 sect1
元素确实找到了匹配的模板。
清单2的B部分
在没有模式的情况下调用Apply-templates
来呈现内容本身。
清单2的C部分
这将在toc
模式下处理section元素。 它使用标题作为链接的URL片段标识符来打印标题。
清单2的D部分
该模板在呈现内容本身时处理这些部分。 标题用作链接锚,标题也用作锚名称。
其余的转换非常简单。 设置模板是为了在常规模板处理期间禁止显示title元素,因为已经使用xsl:value-of
明确显示了标题元素。 清单3演示了转换。
[uogbuji@borgia tip-internal-links]$ 4xslt xml1 xslt1
<html>
<head>
<META HTTP-EQUIV='Content-Type'
content='text/html; charset=UTF-8'>
</head>
<body>
<h2>Contents</h2>
<a href='#Elizabethan'>Elizabethan</a>
<br>
<a href='#Jacobean'>Jacobean</a>
<br>
<a href='#Georgian'>Georgian</a>
<br>
<hr>
<div>
<h2>
<a name='Elizabethan'>Elizabethan</a>
</h2>
<p>Shakespeare his histories, Jonson his charlatans.</p>
</div>
<div>
<h2>
<a name='Jacobean'>Jacobean</a>
</h2>
<p>"Webster was much possessed by death..."</p>
</div>
<div>
<h2>
<a name='Georgian'>Georgian</a>
</h2>
<p>
Shaw the sly subversive. Fabian and common sense storyteller.
</p>
</div>
</body>
</html>
[uogbuji@borgia tip-internal-links]$
请注意,此方法取决于您在字符数据字段中有一个方便且唯一的字符串。 理想情况下,这将是ID
类型的属性,以便XML解析器可以确保您的唯一性。 同样,类型ID
属性具有格式限制,使其适合用作URL片段标识符。
使用generate-id()
不幸的是,在命名锚点和内部链接时并不总是需要方便的领域。 以清单4中的文档为例,它也是DocBook形式。
<?xml version='1.0'?>
<article>
<sect1>
<title>The Burial of the Dead</title>
<para>
Summer surprised us that day, coming over the Starnbergensee.
</para>
</sect1>
<sect1>
<title>A Game of Chess</title>
<para>
But O O O O that Shakespeherian rag.
It's so elegant, so intelligent.
</para>
</sect1>
<sect1>
<title>Death by Water</title>
<para>
He passed the stages of his age and youth /
Entering the whirlpool.
</para>
</sect1>
</article>
清单4中的第二个DocBook示例具有部分标题,但是这次它们不适合用作链接名称。 一方面,它们包含空格,这些空格将由XSLT处理器转换为难看的URL,除非它们很长,否则可能不会很糟糕。 该长度也可能导致用户代理出现问题。 在这种情况下,如果没有这种潜在的陷阱,我们就没有方便的领域。 可以使用一些功能强大的XSLT将标识符修补在一起,但是幸运的是,还有另一种方法。
当您需要生成内部链接时,没有方便的字段是唯一的,始终可用的并且没有适用于URL片段的形式,则可以使用XSLT的功能为给定的节点为您生成唯一的ID。 在XSLT规范中定义的generate-id()
函数(请参阅参考资料 ),获取一个节点集并返回一个字符串,该字符串表示从该集合中的第一个节点按文档顺序生成的标识符。 该标识符具有两个重要的属性:保证对于不同的参数节点是不同的,并且对于相同的参数节点,它是相同的。
掌握了这些知识,就可以编写类似于清单5中的转换。
<?xml version="1.0"?>
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:template match="/">
<html>
<head/>
<body>
<h2>Contents</h2>
<xsl:apply-templates mode="toc"/>
<hr/>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<!-- A -->
<xsl:template match="sect1" mode="toc">
<a href="#{generate-id()}"><xsl:value-of select="title"/></a><br/>
</xsl:template>
<!-- B -->
<xsl:template match="sect1">
<div>
<h2><a name="{generate-id()}">
<xsl:value-of select="title"/>
</a></h2>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="title"/>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:transform>
清单5的A部分
现在,不是使用元素的内容指定链接,而是使用generate-id()
函数。 没有传入任何节点集,因此当前节点用于生成节点集。 当前节点是文档每个部分的sect1
元素。
清单5的B部分
同样, sect1
节点用于生成一个ID,对于每个节点,该ID与在页面顶部相应链接中生成的ID相同。
清单6显示了转换的输出。
清单6.上一个清单中转换的输出
[uogbuji@borgia tip-internal-links]$ 4xslt xml2 xslt2
<html>
<head>
<META HTTP-EQUIV='Content-Type'
content='text/html; charset=UTF-8'></head>
<body>
<h2>Contents</h2>
<a href='#id137055808'>The Burial of the Dead</a>
<br>
<a href='#id137023880'>A Game of Chess</a>
<br>
<a href='#id137262848'>Death by Water</a>
<br>
<hr>
<div>
<h2>
<a name='id137055808'>The Burial of the Dead</a>
</h2>
<p>Summer surprised us that day,
coming over the Starnbergensee.</p> </div>
<div>
<h2>
<a name='id137023880'>A Game of Chess</a>
</h2>
<p>But O O O O that Shakespeherian rag.
It's so elegant, so intelligent.</p>
</div>
<div>
<h2>
<a name='id137262848'>Death by Water</a>
</h2>
<p>He passed the stages of his age and youth /
Entering the whirlpool.</p>
</div>
</body>
</html>
[uogbuji@borgia tip-internal-links]$
结论
您可以通过多种方法将这种技术用于内部链接的自动化。 长文档只是一个例子。 如何使用它为FAQ页面建立索引? 实际上,我在4Suite.org上帮助整理的FAQ页面使用了generate-id()
方法来提供FAQ摘要,该摘要在内部链接到各个FAQ条目。 您可以在动态网页中使用它来为每个页面视图一致地创建内部链接。 我敢肯定,这些方法会派上用场。
翻译自: https://www.ibm.com/developerworks/xml/library/x-tipxslt/index.html
xslt生成序号