Skip to content

Commit

Permalink
Support constructing glossary divisions automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
ndw committed Jan 30, 2024
1 parent b61ca82 commit a409299
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 27 deletions.
9 changes: 3 additions & 6 deletions src/guide/xml/ch03.xml
Original file line number Diff line number Diff line change
Expand Up @@ -738,12 +738,9 @@ check whether a corresponding <code>glossentry</code> exists for a
<code>glossterm</code> or <code>firstterm</code> while you are still
writing. Corresponding Schematron schemas are not yet part of the
xslTNG framework.</para>

<simplesect>
<title>Caveats</title>
<para>The use of <code>glossdiv</code> is not supported for automatic glossaries, all
of the entries will appear in a flat list.</para>
</simplesect>

<para>Generating glossary divisions automatically is controlled by the
<parameter>glossary-automatic-divisions</parameter> parameter.</para>
</section>

<section xml:id="different">
Expand Down
39 changes: 37 additions & 2 deletions src/guide/xml/ref-params.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2022,22 +2022,57 @@ the first term is used.</para>
<refmeta>
<fieldsynopsis>
<varname>glossary-sort-entries</varname>
<initializer>true()</initializer>
<initializer>'true'</initializer>
</fieldsynopsis>
</refmeta>
<refnamediv>
<refpurpose>Sort glossaries?</refpurpose>
</refnamediv>
<refsection>
<title>Description</title>
<para>If <parameter>glossary-sort-entries</parameter> is true, the entries in a
<para>If <parameter>glossary-sort-entries</parameter> <glossterm>is true</glossterm>, the entries in a
<tag>glossary</tag> or <tag>glosslist</tag> will be sorted before transformation.
This saves the author from the burden of maintaining the list in a strictly
alphabetic order.
</para>
</refsection>
</refentry>

<refentry>
<refmeta>
<fieldsynopsis>
<varname>glossary-automatic-divisions</varname>
<initializer>'false'</initializer>
</fieldsynopsis>
</refmeta>
<refnamediv>
<refpurpose>Divide glossaries into sections?</refpurpose>
</refnamediv>
<refsection>
<title>Description</title>
<para>If <parameter>glossary-automatic-divisions</parameter> <glossterm>is true</glossterm>,
the entries in an automatically constructed glossary will be grouped. The actual grouping
is performed by the <template>t:glossary-divisions</template> template. This parameter is
false by default for backwards compatibility.
</para>

<para>Automatic divisions can be specified on a per-glossary basis with a
<literal>db</literal> processing instruction
<indexterm>
<primary>db processing instruction</primary>
</indexterm> using the <literal>glossary-divisions</literal><indexterm>
<primary>db processing instruction</primary>
<secondary>glossary-divisions pseudo-attribute</secondary>
</indexterm>
pseudo-attribute with a value of <code>true</code> or <code>false</code>.</para>

<para>This parameter only applies if
<parameter>glossary-sort-entries</parameter> <glossterm>is true</glossterm> and the glossary
is not already grouped with <tag>glossdiv</tag> elements by hand.
</para>
</refsection>
</refentry>

<refentry>
<refmeta>
<fieldsynopsis>
Expand Down
21 changes: 21 additions & 0 deletions src/guide/xml/ref-templates.xml
Original file line number Diff line number Diff line change
Expand Up @@ -665,4 +665,25 @@ element with an <att>xlink:href</att> attribute) and extended links.
</refsection>
</refentry>

<refentry xml:id="t_glossary-divisions">
<?db filename="t_glossary-divisions"?>
<refmeta>
<refentrytitle>t:glossary-divisions</refentrytitle>
<refmiscinfo>{http://docbook.org/ns/docbook/templates}glossary-divisions</refmiscinfo>
</refmeta>
<refnamediv>
<refname>t:glossary-divisions</refname>
<refpurpose>Groups entries in a glossary</refpurpose>
<refclass>template</refclass>
</refnamediv>
<refsection>
<title>Description</title>
<para>If <parameter>glossary-automatic-divisions</parameter> <glossterm>is true</glossterm>,
this template is used to construct the divisions. By default, it makes groups based on the
(upper-case) first letter of the terms. It does not add a grouping wrapper if there’s only
one group.
</para>
</refsection>
</refentry>

</reference>
5 changes: 4 additions & 1 deletion src/main/scss/media-all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1506,11 +1506,14 @@ li[db-mark='box'] {

/* ============================================================ */


.glossdiv {
margin-top: 1em;
}

.glossdiv dl dt {
padding-left: 1em;
}

/* ============================================================ */

.sidebar {
Expand Down
67 changes: 58 additions & 9 deletions src/main/xslt/modules/glossary.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,76 @@
<xsl:variable name="gi" select="if (parent::*)
then 'div'
else 'article'"/>

<xsl:variable name="make-divisions"
select="if (empty(f:pi(., 'glossary-divisions', ())))
then f:is-true($glossary-automatic-divisions)
else f:is-true(f:pi(., 'glossary-divisions', 'false'))"/>

<xsl:element name="{$gi}" namespace="http://www.w3.org/1999/xhtml">
<xsl:apply-templates select="." mode="m:attributes"/>
<xsl:apply-templates select="." mode="m:generate-titlepage"/>
<xsl:apply-templates select="* except (db:glossentry|db:bibliography)"/>
<dl class="{local-name(.)}">
<xsl:choose>
<xsl:when test="$glossary-sort-entries">
<xsl:choose>
<xsl:when test="self::db:glossary and db:glossentry
and f:is-true($glossary-sort-entries) and $make-divisions">
<xsl:call-template name="t:glossary-divisions">
<xsl:with-param name="terms" as="element(db:glossentry)+">
<xsl:for-each select="db:glossentry">
<xsl:sort select="(@sortas, normalize-space(db:glossterm[1]))[1]"
collation="{$sort-collation}"/>
<xsl:sequence select="."/>
</xsl:for-each>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="db:glossentry and f:is-true($glossary-sort-entries)">
<dl class="{local-name(.)}">
<xsl:apply-templates select="db:glossentry">
<xsl:sort select="(@sortas, normalize-space(db:glossterm[1]))[1]"
collation="{$sort-collation}"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="db:glossentry"/>
</xsl:otherwise>
</xsl:choose>
</dl>
</dl>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="db:glossentry"/>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="db:bibliography"/>
</xsl:element>
</xsl:template>

<xsl:template name="t:glossary-divisions">
<xsl:param name="terms" as="element(db:glossentry)+"/>

<xsl:variable name="gid" select="f:id(.)"/>

<xsl:for-each-group
select="$terms"
group-by="upper-case(substring((db:glossterm[1]/@baseform, string(db:glossterm[1]))[1], 1, 1))">
<xsl:choose>
<!-- Don't bother with the group in the unlikely event that there's only one. -->
<xsl:when test="last() gt 1">
<div id="{$gid}_{current-grouping-key()}" class="glossdiv">
<header>
<div class="title">
<xsl:sequence select="current-grouping-key()"/>
</div>
</header>
<dl>
<xsl:apply-templates select="current-group()"/>
</dl>
</div>
</xsl:when>
<xsl:otherwise>
<dl>
<xsl:apply-templates select="current-group()"/>
</dl>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>

<xsl:template match="db:glossentry">
<dt>
<xsl:apply-templates select="." mode="m:attributes"/>
Expand Down
6 changes: 3 additions & 3 deletions src/main/xslt/transforms/50-normalize.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,14 @@
</xsl:template>

<xsl:template match="db:glossary">
<xsl:variable name="glossary">
<xsl:variable name="glossary" as="element(db:glossary)">
<xsl:call-template name="tp:normalize-generated-title">
<xsl:with-param name="title-key" select="local-name(.)"/>
</xsl:call-template>
</xsl:variable>

<xsl:choose>
<xsl:when test="$glossary/db:glossary[@role = 'auto']">
<xsl:when test="$glossary[@role = 'auto']">
<xsl:variable name="terms" as="element()*">
<xsl:for-each-group select="//db:glossterm[not(ancestor::db:glossary)] union //db:firstterm"
group-by="(@baseform, normalize-space())[1]">
Expand All @@ -175,7 +175,7 @@
</xsl:variable>
<xsl:if test="exists($terms)">
<glossary xmlns="http://docbook.org/ns/docbook">
<xsl:sequence select="$glossary/*/@*, $glossary/*/db:info"/>
<xsl:sequence select="$glossary/@*, $glossary/node() except $glossary/db:glossentry"/>
<xsl:call-template name="t:glossary-content">
<xsl:with-param name="terms" select="$terms"/>
</xsl:call-template>
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/expected/glossary.001.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@
flowering vine in the family Piperaceae, cultivated for its fruit, which is usually
dried and used as a spice and seasoning. Long pepper has a taste similar to, but sweeter
and less pungent than, that of its close relative Piper nigrum – from which black, green
and white pepper are obtained. </p></dd></dl></div><dl class="glossary"></dl></div></article></main><nav class="bottom"></nav></body></html>
and white pepper are obtained. </p></dd></dl></div></div></article></main><nav class="bottom"></nav></body></html>
8 changes: 4 additions & 4 deletions src/test/resources/expected/glossary.008.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
<em>Quince</em> or <em>Bloodroot</em> in the results document
glossary, although there is an entry in the internal glossary of the input document, because
there is no <em>glossterm</em> or <em>firstterm</em> that references
it.</p><div id="R_g1" class="auto component glossary"><header><h2>Glossary</h2></header><dl class="glossary"><dt id="R_g1_ge1" class="glossentry"><span class="glossterm">Apple</span></dt><dd class="glossdef"><p>In early autumn the apple orchards come alive with people and sounds. The
it.</p><div id="R_g1" class="auto component glossary"><header><h2>Glossary</h2></header><div id="R_g1_A" class="glossdiv"><header><div class="title">A</div></header><dl><dt id="R_g1_ge1" class="glossentry"><span class="glossterm">Apple</span></dt><dd class="glossdef"><p>In early autumn the apple orchards come alive with people and sounds. The
farmers are picking, peeling, and processing apples into everything from apple
pies to apple sauce. Families swarm the apple trees with their baskets looking
for the best Honeycrisp and Macintosh. The sound of children playing is blended
with the occasional barking dog, or the low rumble of the old Ferguson Orchard
tractor pulling a wagon up and down the rows. </p></dd><dt id="R_g1_ge3" class="glossentry"><span class="glossterm">Cucumber</span></dt><dd class="glossdef"><p>The cucumber (Cucumis sativus) is a widely-cultivated creeping vine plant in the family
tractor pulling a wagon up and down the rows. </p></dd></dl></div><div id="R_g1_C" class="glossdiv"><header><div class="title">C</div></header><dl><dt id="R_g1_ge3" class="glossentry"><span class="glossterm">Cucumber</span></dt><dd class="glossdef"><p>The cucumber (Cucumis sativus) is a widely-cultivated creeping vine plant in the family
Cucurbitaceae that bears cylindrical to spherical fruits, which are used as culinary
vegetables. Considered an annual plant, there are three main types of cucumber—slicing,
pickling, and seedless—within which several cultivars have been created. The cucumber
originates in Asia extending from India, Nepal, Bangladesh, China (Yunnan, Guizhou,
Guangxi), and Northern Thailand, but now grows on most continents, and many different types
of cucumber are grown commercially and traded on the global market. In North America, the
term wild cucumber refers to plants in the genera Echinocystis and Marah, though the two are
not closely related.</p></dd><dt id="pear" class="glossentry"><span class="glossterm">Pear</span></dt><dd class="glossdef"><p>The pear tree and shrub are a species of genus
not closely related.</p></dd></dl></div><div id="R_g1_P" class="glossdiv"><header><div class="title">P</div></header><dl><dt id="pear" class="glossentry"><span class="glossterm">Pear</span></dt><dd class="glossdef"><p>The pear tree and shrub are a species of genus
Pyrus, in the family Rosaceae, bearing the pomaceous
fruit of the same name. Several species of pear are valued for
their edible fruit and juices while others are cultivated as
trees.</p></dd></dl></div></article></main><nav class="bottom"></nav></body></html>
trees.</p></dd></dl></div></div></article></main><nav class="bottom"></nav></body></html>
2 changes: 1 addition & 1 deletion src/test/resources/expected/titles.001.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</p></div></div></div></div></div></div></div></section></article><section id="app" class="appendix component"><header><h2>Appendix <span class="label">A</span><span class="sep"></span>Appendix</h2></header><p></p></section><section id="app2" class="appendix component"><header><h2>Appendix <span class="label">B</span><span class="sep"></span>Appendix Two</h2></header><div id="bibliolist" class="bibliolist"><header><div class="title">bibliolist</div></header>

<p id="bibliomixed" class="bibliomixed">[bibliomixed] a bibliomixed</p>
</div><div id="glosslist" class="glosslist"><header><div class="title">Gloss list</div></header><dl class="glosslist"><dt id="glosslist_ge1" class="glossentry"><span class="glossterm">Thing</span></dt><dd class="glossdef"><p></p></dd></dl></div></section><div id="bibliography" class="bibliography component"><header><h2>Bibliography</h2></header><div id="bibliodiv" class="bibliodiv"><header><h3>Bibliography division</h3></header><p id="bibliomixed2" class="bibliomixed">[bibliomixed2] a bibliomixed</p></div></div><div id="glossary" class="component glossary"><header><h2>Glossary</h2></header><div id="glossdiv" class="glossdiv"><header><div class="title">Glossary division</div></header><dl class="glossdiv"><dt id="glossdiv_ge1" class="glossentry"><span class="glossterm">Thing</span></dt><dd class="glossdef"><p></p></dd></dl></div><dl class="glossary"></dl></div><div id="index" class="component index"><header><h2>Index</h2></header><div class="index-list"><div class="generated-index"><div class="generated-indexdiv"><header><h3>O</h3></header><ul><li>one, <span class="indexed-section" title=""><a class="indexref" href="#ch1_info1_title1_indexterm1">1</a></span>, <span class="indexed-section" title=""><a class="indexref" href="#ch2_info1_title1_indexterm1">1</a></span></li></ul></div></div></div></div><section id="acknowledgements" class="acknowledgements component"><header><h2>Acknowledgements</h2></header>
</div><div id="glosslist" class="glosslist"><header><div class="title">Gloss list</div></header><dl class="glosslist"><dt id="glosslist_ge1" class="glossentry"><span class="glossterm">Thing</span></dt><dd class="glossdef"><p></p></dd></dl></div></section><div id="bibliography" class="bibliography component"><header><h2>Bibliography</h2></header><div id="bibliodiv" class="bibliodiv"><header><h3>Bibliography division</h3></header><p id="bibliomixed2" class="bibliomixed">[bibliomixed2] a bibliomixed</p></div></div><div id="glossary" class="component glossary"><header><h2>Glossary</h2></header><div id="glossdiv" class="glossdiv"><header><div class="title">Glossary division</div></header><dl class="glossdiv"><dt id="glossdiv_ge1" class="glossentry"><span class="glossterm">Thing</span></dt><dd class="glossdef"><p></p></dd></dl></div></div><div id="index" class="component index"><header><h2>Index</h2></header><div class="index-list"><div class="generated-index"><div class="generated-indexdiv"><header><h3>O</h3></header><ul><li>one, <span class="indexed-section" title=""><a class="indexref" href="#ch1_info1_title1_indexterm1">1</a></span>, <span class="indexed-section" title=""><a class="indexref" href="#ch2_info1_title1_indexterm1">1</a></span></li></ul></div></div></div></div><section id="acknowledgements" class="acknowledgements component"><header><h2>Acknowledgements</h2></header>

<p></p>
</section><section id="colophon" class="colophon component"><header><h2>Colophon</h2></header><p></p></section></article><footer><div class="footnotes"><hr/><div class="footnote" id="ch2_info1_title1_footnote1-fnote"><div class="footnote-number"><sup class="footnote-number"><a href="#ch2_info1_title1_footnote1-fref">1</a></sup></div><div class="footnote-body"><p>Yeah, really.</p></div></div></div></footer></main><nav class="bottom"></nav></body></html>
1 change: 1 addition & 0 deletions src/test/resources/xml/glossary.008.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ setting the <parameter>glossary-collection</parameter> parameter.</para>
it.</para>

<glossary role="auto">
<?db glossary-divisions="true"?>
<glossentry>
<glossterm>Quince</glossterm>
<glossdef>
Expand Down
67 changes: 67 additions & 0 deletions src/test/resources/xml/glossary.010.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0">
<info>
<?db toc="false"?>
<title>Unit Test: glossary.010</title>
<editor>
<personname>
<firstname>Someone</firstname>
<surname>Random</surname>
</personname>
</editor>
<subtitle>Wikipedia fruits with pepper</subtitle>
<releaseinfo>Just some test data</releaseinfo>
<othercredit><orgname>Wikimedia Commons</orgname></othercredit>
</info>

<chapter>
<title>Fruits and Peppers</title>

<note>
<para>The test harness is configured to run this test with the
<parameter>glossary-collection</parameter> parameter pointing to
<filename>src/test/resources/glosscollection.xml</filename>.</para>
</note>

<para><glossterm baseform="Peach">Peaches</glossterm>,
<glossterm baseform="Pear">Pears</glossterm>, and
<glossterm baseform="Pepper">Peppers</glossterm>.</para>
</chapter>

<glossary xml:id="glossary" role="auto">
<?db glossary-divisions="true"?>
<glossentry>
<glossterm>Pepper</glossterm>
<glossdef>
<para>Black pepper (Piper nigrum) is a flowering vine in the family Piperaceae, cultivated for
its fruit (the peppercorn), which is usually dried and used as a spice and seasoning.
Peppercorns and the ground pepper derived from them may be described simply as pepper,
or more precisely as <emphasis>black pepper</emphasis> (cooked and dried unripe fruit),
<emphasis>green pepper</emphasis> (dried unripe fruit), or <emphasis>white pepper
</emphasis>(ripe fruit seeds).</para>
</glossdef>
</glossentry>

<glossentry xml:id="peach">
<glossterm>Peach</glossterm>
<glossdef>
<para>The peach (Prunus persica) is a deciduous tree native to the
region of Northwest China between the Tarim Basin and the north
slopes of the Kunlun Mountains, where it was first domesticated
and cultivated. It bears an edible juicy fruit called a peach
or a nectarine.</para>
</glossdef>
</glossentry>

<glossentry xml:id="pear">
<glossterm>Pear</glossterm>
<glossdef>
<para>The pear tree and shrub are a species of genus
Pyrus, in the family Rosaceae, bearing the pomaceous
fruit of the same name. Several species of pear are valued for
their edible fruit and juices while others are cultivated as
trees.</para>
</glossdef>
</glossentry>
</glossary>
</book>

0 comments on commit a409299

Please sign in to comment.