此词汇表从每个条目的第一个字母派生索引。我正试图弄清楚如何只展示独特的价值观。已经研究过previous-sibling和position()但似乎无法找到正确的方法。我受限于使用XSLT 1.0和属性。
glossary.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="glossary.xsl"?>
<include>
<file name="data.xml"/>
</include>
data.xml中
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<glossary>
<entry term="cantaloupe" definition="A kind of melon"/>
<entry term="banana" definition="A tropical yellow fruit"/>
<entry term="apple" definition="A red fruit with seeds"/>
<entry term="orange" definition="An orange citrus fruit"/>
<entry term="Cherry" definition="A red fruit that grows in clusters "/>
<entry term="cranberry" definition="A sour berry enjoyed at Thanksgiving"/>
<entry term="avocado" definition="A mellow fruit enjoyed in guacamole"/>
</glossary>
glossary.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<html>
<head></head>
<body>
<!-- Index: how to show unique values? -->
<xsl:for-each select="document('data.xml')/glossary/entry" >
<xsl:sort select="@term" data-type="text" order="ascending" case-order="upper-first"/>
<xsl:variable name="initial" select="substring(@term,1,1)" />
<a href="#{$initial}"><xsl:value-of select="$initial" /></a> |
</xsl:for-each>
<!-- Glossary -->
<dl>
<xsl:for-each select="document('data.xml')/glossary/entry" >
<xsl:sort select="@term" data-type="text" order="ascending" case-order="upper-first"/>
<xsl:variable name="initial" select="substring(@term,1,1)" />
<!-- Alphabetical header: how to only the first instance of each letter? -->
<a name="{$initial}"><h1><xsl:value-of select="$initial" /></h1></a>
<dt><xsl:apply-templates select="@term"/></dt>
<dd><xsl:apply-templates select="@definition"/></dd>
</xsl:for-each>
</dl>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
到目前为止的输出
a | a | b | c | C | c | o |
一个
苹果
带种子的红色水果
一个
鳄梨
瓜果酱中的醇厚果实
b
香蕉
热带黄色水果
ç
哈密瓜
一种甜瓜
ç
樱桃
一种生长成簇的红色水果
ç
蔓越莓
在感恩节享受的酸浆果
Ø
橙色
橙色柑橘类水果
期望的输出
a | b | c | o
一个
苹果
带种子的红色水果
鳄梨
在鳄梨酱中享用的醇厚果实
b
香蕉
热带黄色水果
Ç
哈密瓜
一种甜瓜
樱桃
一种生长成簇的红色水果
蔓越莓
在感恩节享用酸浆果
0
橙色
橙子柑橘子
答案 0 :(得分:2)
您需要的技术称为 Muenchian分组。首先定义一个键,它按照术语
的下标首字母对条目元素进行分组<xsl:key name="entryByInitial" match="entry" use="translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
然后你使用generate-id
的技巧只提取匹配每个键的第一个元素
<xsl:for-each select="document('data.xml')">
<!-- iterate over the "groups" to build the top links -->
<xsl:for-each select="glossary/entry[generate-id() = generate-id(key('entryByInitial', translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))[1])]">
<xsl:sort select="translate(@term, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" data-type="text" order="ascending"/>
<xsl:variable name="initial" select="translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
<!-- insert a leading | before all but the first link -->
<xsl:if test="position() > 1"> | </xsl:if>
<a href="#{$initial}"><xsl:value-of select="$initial" /></a>
</xsl:for-each>
<!-- iterate over the groups again -->
<xsl:for-each select="glossary/entry[generate-id() = generate-id(key('entryByInitial', translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))[1])]">
<xsl:sort select="translate(@term, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" data-type="text" order="ascending"/>
<xsl:variable name="initial" select="translate(substring(@term, 1, 1), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
<a name="{$initial}"><h1><xsl:value-of select="$initial" /></h1></a>
<dl>
<!-- apply templates for all entries with this key value -->
<xsl:apply-templates select="key('entryByInitial', $initial)">
<xsl:sort select="translate(@term, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" data-type="text" order="ascending"/>
</xsl:apply-templates>
</dl>
</xsl:for-each>
</xsl:for-each>
并定义一个单独的模板
<xsl:template match="entry">
<dt><xsl:apply-templates select="@term"/></dt>
<dd><xsl:apply-templates select="@definition"/></dd>
</xsl:template>
答案 1 :(得分:2)
这是分组问题的一个例子,在XSLT 1.0中,已建立的分组方法是使用Muenchian分组。不幸的是,您的场景需要在此基础上找到小写字符,并且在XSLT 1.0中有点混乱。
尽管如此,我已经制作了一个解决方案,其内容如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-system="about:legacy-compat"
encoding="UTF-8" indent="yes" />
<xsl:key name="kEntryInitial" match="entry/@term"
use="translate(substring(., 1, 1),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')"/>
<xsl:template match="/">
<html>
<head></head>
<body>
<!-- Jump into the data.xml DOM so that keys work -->
<xsl:apply-templates select="document('data.xml')/glossary" />
</body>
</html>
</xsl:template>
<xsl:template match="/glossary">
<!-- Select terms with distinct initials (case invariant) -->
<xsl:variable name="termsByDistinctInitial"
select="entry/@term[generate-id() =
generate-id(key('kEntryInitial',
translate(substring(., 1, 1),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'))[1])]" />
<!-- Header -->
<xsl:apply-templates select="$termsByDistinctInitial" mode="header">
<xsl:sort select="." data-type="text" order="ascending" />
</xsl:apply-templates>
<!-- Glossary -->
<dl>
<xsl:apply-templates select="$termsByDistinctInitial" mode="main">
<xsl:sort select="." data-type="text" order="ascending" />
</xsl:apply-templates>
</dl>
</xsl:template>
<xsl:template match="@term" mode="header">
<xsl:variable name="initial">
<xsl:call-template name="ToLower">
<xsl:with-param name="value" select="substring(., 1, 1)" />
</xsl:call-template>
</xsl:variable>
<a href="#{$initial}">
<xsl:value-of select="$initial" />
</a>
<xsl:if test="position() != last()">
<xsl:text> |</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="@term" mode="main">
<xsl:variable name="initial">
<xsl:call-template name="ToLower">
<xsl:with-param name="value" select="substring(., 1, 1)" />
</xsl:call-template>
</xsl:variable>
<a name="{$initial}">
<h1>
<xsl:value-of select="$initial" />
</h1>
</a>
<xsl:apply-templates select="key('kEntryInitial', $initial)/.." />
</xsl:template>
<xsl:template match="entry">
<dt>
<xsl:apply-templates select="@term"/>
</dt>
<dd>
<xsl:apply-templates select="@definition"/>
</dd>
</xsl:template>
<xsl:template name="ToLower">
<xsl:param name="value" />
<xsl:value-of select="translate(substring($value, 1, 1),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')"/>
</xsl:template>
</xsl:stylesheet>
在输入XML上运行时,会产生以下结果:
<!DOCTYPE html SYSTEM "about:legacy-compat">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body><a href="#a">a</a> |<a href="#b">b</a> |<a href="#c">c</a> |<a href="#o">o</a>
<dl><a name="a"><h1>a</h1></a><dt>apple</dt>
<dd>A red fruit with seeds</dd>
<dt>avocado</dt>
<dd>A mellow fruit enjoyed in guacamole</dd><a name="b"><h1>b</h1></a><dt>banana</dt>
<dd>A tropical yellow fruit</dd><a name="c"><h1>c</h1></a><dt>cantaloupe</dt>
<dd>A kind of melon</dd>
<dt>Cherry</dt>
<dd>A red fruit that grows in clusters </dd>
<dt>cranberry</dt>
<dd>A sour berry enjoyed at Thanksgiving</dd><a name="o"><h1>o</h1></a><dt>orange</dt>
<dd>An orange citrus fruit</dd>
</dl>
</body>
</html>
我建议考虑的一件事是使用简单的XSLT来准备&#34;准备&#34;你的词汇表有缩写:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="entry">
<xsl:copy>
<xsl:attribute name="initial">
<xsl:value-of select="translate(substring(@term, 1, 1),
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')"/>
</xsl:attribute>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这会产生:
<glossary>
<entry initial="c" term="cantaloupe" definition="A kind of melon" />
<entry initial="b" term="banana" definition="A tropical yellow fruit" />
<entry initial="a" term="apple" definition="A red fruit with seeds" />
<entry initial="o" term="orange" definition="An orange citrus fruit" />
<entry initial="c" term="Cherry" definition="A red fruit that grows in clusters " />
<entry initial="c" term="cranberry" definition="A sour berry enjoyed at Thanksgiving" />
<entry initial="a" term="avocado" definition="A mellow fruit enjoyed in guacamole" />
</glossary>
然后,如果你使用这个准备版本作为术语表,那么主要的XSLT可以摆脱所有那些丑陋的translate()
函数并变得更加清晰:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-system="about:legacy-compat"
encoding="UTF-8" indent="yes" />
<xsl:key name="kEntryInitial" match="entry/@initial" use="."/>
<xsl:template match="/">
<html>
<head></head>
<body>
<!-- Jump into the data.xml DOM so that keys work -->
<xsl:apply-templates select="document('data2.xml')/glossary" />
</body>
</html>
</xsl:template>
<xsl:template match="/glossary">
<!-- Select terms with distinct initials (case invariant) -->
<xsl:variable name="termsByDistinctInitial"
select="entry/@initial[generate-id() =
generate-id(key('kEntryInitial', .)[1])]" />
<!-- Header -->
<xsl:apply-templates select="$termsByDistinctInitial" mode="header">
<xsl:sort select="." data-type="text" order="ascending" />
</xsl:apply-templates>
<!-- Glossary -->
<dl>
<xsl:apply-templates select="$termsByDistinctInitial" mode="main">
<xsl:sort select="." data-type="text" order="ascending" />
</xsl:apply-templates>
</dl>
</xsl:template>
<xsl:template match="@initial" mode="header">
<a href="#{.}">
<xsl:value-of select="." />
</a>
<xsl:if test="position() != last()">
<xsl:text> |</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="@initial" mode="main">
<a name="{.}">
<h1>
<xsl:value-of select="." />
</h1>
</a>
<xsl:apply-templates select="key('kEntryInitial', .)/.." />
</xsl:template>
<xsl:template match="entry">
<dt>
<xsl:apply-templates select="@term"/>
</dt>
<dd>
<xsl:apply-templates select="@definition"/>
</dd>
</xsl:template>
</xsl:stylesheet>
当然,最终输出与第一个例子相同。如果您的XSLT处理器支持node-set()
功能,那么也可以在单个XSLT中执行这两个处理步骤。