Skip to content

Commit 4321e46

Browse files
author
Sanders Kleinfeld
committed
Merge pull request #110 from oreillymedia/xspec
NCX improvements and Xspec tests
2 parents 87e4020 + f4d1547 commit 4321e46

File tree

4 files changed

+192
-34
lines changed

4 files changed

+192
-34
lines changed

htmlbook-xsl/epub.xsl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@
167167
<!-- ID to use in the manifest for the NCX TOC (if $generate.ncx.toc is enabled) -->
168168
<xsl:param name="ncx.toc.id">toc.ncx</xsl:param>
169169

170+
<!-- Specify how many levels of sections to include in NCX TOC.
171+
An $ncx.toc.section.depth of 0 indicates only chapter-level headings and above to be included in NCX TOC
172+
An $ncx.toc.section depth of 1 indicates only sect1-level headings and above to be included in NCX TOC
173+
And so on...
174+
-->
175+
<xsl:param name="ncx.toc.section.depth" select="4"/>
176+
170177
<!-- Include labels in NCX TOC? -->
171178
<xsl:param name="ncx.toc.include.labels" select="1"/>
172179

htmlbook-xsl/ncx.xsl

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
</xsl:template>
3434

3535
<xsl:template name="generate.ncx.toc.content">
36+
<xsl:param name="toc.node" select="/*"/>
37+
<xsl:param name="generate.cover.html" select="$generate.cover.html"/>
3638
<ncx version="2005-1">
3739
<head>
3840
<xsl:if test="$generate.cover.html = 1">
@@ -63,7 +65,7 @@
6365
<content src="{$root.chunk.filename}"/>
6466
</navPoint>
6567
</xsl:if>
66-
<xsl:apply-templates select="/*" mode="ncx.toc.gen"/>
68+
<xsl:apply-templates select="$toc.node" mode="ncx.toc.gen"/>
6769
</navMap>
6870
</xsl:variable>
6971
<xsl:apply-templates select="exsl:node-set($navMap)" mode="output.navMap.with.playOrder"/>
@@ -76,11 +78,14 @@
7678
</xsl:template>
7779

7880
<xsl:template match="h:section[not(@data-type = 'dedication' or @data-type = 'titlepage' or @data-type = 'toc' or @data-type = 'colophon' or @data-type = 'copyright-page' or @data-type = 'halftitlepage')]|h:div[@data-type='part']" mode="ncx.toc.gen">
79-
<xsl:call-template name="generate.navpoint"/>
81+
<xsl:if test="not(self::h:section[contains(@data-type, 'sect') and htmlbook:section-depth(.) != '' and htmlbook:section-depth(.) &gt; $ncx.toc.section.depth])">
82+
<xsl:call-template name="generate.navpoint"/>
83+
</xsl:if>
8084
</xsl:template>
8185

8286
<!-- Only put the Nav doc in the NCX TOC if $nav.in.ncx is enabled -->
8387
<xsl:template match="h:nav[@data-type='toc']" mode="ncx.toc.gen">
88+
<xsl:param name="nav.in.ncx" select="$nav.in.ncx"/>
8489
<xsl:if test="$nav.in.ncx = 1">
8590
<xsl:call-template name="generate.navpoint"/>
8691
</xsl:if>
@@ -104,6 +109,10 @@
104109

105110
<xsl:template name="generate.navpoint">
106111
<xsl:param name="node" select="."/>
112+
113+
<!-- Primarily included for xspec testing, but allows for the possibility of toggling labeling for individual navPoints -->
114+
<xsl:param name="ncx.toc.include.labels" select="$ncx.toc.include.labels"/>
115+
107116
<!-- Traverse down the tree and process descendant navpoints? Default is "yes" -->
108117
<xsl:param name="process-descendants" select="1"/>
109118
<navPoint>
@@ -122,7 +131,11 @@
122131
<xsl:value-of select="$label.and.title.separator"/>
123132
</xsl:if>
124133
</xsl:if>
125-
<xsl:apply-templates select="$node" mode="title.markup"/>
134+
<xsl:variable name="title.markup">
135+
<xsl:apply-templates select="$node" mode="title.markup"/>
136+
</xsl:variable>
137+
<!-- Convert to text, as NCX navLabels cannot contain any inline markup -->
138+
<xsl:value-of select="$title.markup"/>
126139
</text>
127140
</navLabel>
128141
<content>

htmlbook-xsl/xspec/ncx.xspec

Lines changed: 165 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,46 +12,184 @@
1212

1313
<!-- Global params for testing -->
1414

15-
<x:pending>
16-
<x:scenario label="When generating full NCX TOC content">
17-
<x:call template="generate.ncx.toc.content"/>
18-
<x:expect label="It should have the standard ncx root element"/>
19-
<x:expect label="It should have a meta element for the cover HTML if generate.cover.html is specified"/>
20-
<x:expect label="It *should not* have a meta element for the cover HTML if generate.cover.html *is not* specified"/>
21-
<x:expect label="It should have the book title in a docTitle element"/>
22-
<x:expect label="It should have a navMap with navPoint children for TOC elements"/>
23-
<x:expect label="NavPoints should have playOrder attributes in consecutive order"/>
15+
<x:param name="metadata.title" select="'Infinite Jest'"/>
16+
17+
<x:param name="label.and.title.separator" select="'. '"/>
18+
19+
<x:param name="label.numeration.by.data-type">
20+
appendix:A
21+
chapter:1
22+
part:I
23+
sect1:none
24+
sect2:none
25+
sect3:none
26+
sect4:none
27+
sect5:none
28+
</x:param>
29+
30+
<x:param name="ncx.toc.section.depth" select="2"/>
31+
32+
<x:scenario label="When generating full NCX TOC content">
33+
<x:call template="generate.ncx.toc.content">
34+
<!-- Test XSL is output to a subdir of the .xspec dir, which also contains skeleton, so relative path contains .. to go up a directory level -->
35+
<x:param name="toc.node" select="document('../skeleton.html')/*"/>
36+
</x:call>
37+
38+
<x:expect label="It should have the standard ncx root element">
39+
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">...</ncx>
40+
</x:expect>
41+
42+
<x:scenario label="With generate.cover.html disabled">
43+
<x:call>
44+
<x:param name="generate.cover.html"/>
45+
</x:call>
46+
<x:expect label="It *should not* have a meta element for the cover HTML" test="not(exists(/ncx:ncx/ncx:head/ncx:meta[@name='cover']))"/>
47+
</x:scenario>
48+
49+
<x:scenario label="With generate.cover.html enabled">
50+
<x:call>
51+
<x:param name="generate.cover.html">1</x:param>
52+
</x:call>
53+
<x:expect label="It should have a meta element for the cover HTML" test="count(/ncx:ncx/ncx:head/ncx:meta[@name='cover']) = 1"/>
2454
</x:scenario>
2555

56+
<x:pending>
57+
<x:scenario label="With ncx.include.root.chunk enabled">
58+
<x:expect label="navPoint for root chunk should be generated"/>
59+
</x:scenario>
60+
61+
<x:scenario label="With ncx.include.root.chunk disabled">
62+
<x:expect label="navPoint for root chunk *should not* be generated"/>
63+
</x:scenario>
64+
</x:pending>
65+
66+
<x:expect label="It should have the book title in a docTitle element" test="exists(/ncx:ncx/ncx:docTitle[. = 'Infinite Jest'])"/>
67+
68+
<x:expect label="It should have a navMap with navPoint children for TOC elements" test="exists(/ncx:ncx/ncx:navMap[ncx:navPoint])"/>
69+
70+
<x:expect label="navPoints should have playOrder attributes in consecutive order"
71+
test="not(exists(//ncx:navPoint[not(@playOrder)])) and
72+
count((//ncx:navPoint)[position() = @playOrder]) = count((//ncx:navPoint))"/>
73+
</x:scenario>
74+
2675
<x:scenario label="When a book section/div is matched in ncx.toc.gen mode">
27-
<x:context/>
28-
<x:expect label="return a NavPoint"/>
76+
<x:context mode="ncx.toc.gen">
77+
<section data-type="chapter">
78+
<h1>Test Chapter</h1>
79+
<p>It was the best of times!</p>
80+
</section>
81+
</x:context>
82+
<x:expect label="return a navPoint">
83+
<ncx:navPoint id="...">...</ncx:navPoint>
84+
</x:expect>
2985

30-
<x:scenario label="When source TOC elements are at a lower level than specified NCX Level">
31-
<x:expect label="Don't generate a NavPoint"/>
86+
<!-- Note: the following test is dependent on the global param set in this xspec document -->
87+
<!-- If test fails, double-check expected value is in sync with these params -->
88+
<x:scenario label="when source TOC elements are at a lower level than specified NCX Level">
89+
<x:context mode="ncx.toc.gen" select="//h:section[@data-type='sect3'][1]">
90+
<section data-type="chapter">
91+
<h1>Test Chapter</h1>
92+
<p>It was the worst of times!</p>
93+
<section data-type="sect1">
94+
<h1>Test Sect1</h1>
95+
<p>Two roads diverged in a wood</p>
96+
<section data-type="sect2">
97+
<h2>Test Sect2</h2>
98+
<p>One fish, two fish, red fish, blue fish</p>
99+
<section data-type="sect3">
100+
<h3>Test SEct3</h3>
101+
<p>It was a dark and stormy night</p>
102+
</section>
103+
</section>
104+
</section>
105+
</section>
106+
</x:context>
107+
<x:expect label="Don't generate a navPoint" test="not(exists(ncx:navPoint))"/>
32108
</x:scenario>
33109
</x:scenario>
34110

35111
<x:scenario label="When a non-book section/div is matched in ncx.toc.gen mode that does not have a book section/div child">
36-
<x:context/>
37-
<x:expect label="Don't generate a NavPoint"/>
112+
<x:context mode="ncx.toc.gen">
113+
<div data-type="note">
114+
<p>Notes should not get navPoints!!!</p>
115+
</div>
116+
</x:context>
117+
<x:expect label="Don't generate a navPoint" test="not(exists(ncx:navPoint))"/>
38118
</x:scenario>
39119

40-
<x:scenario label="When a nav TOC is matched in ncx.toc.gen mode">
41-
<x:context/>
42-
<x:expect label="Generate a NavPoint if $nav.in.ncx is specified"/>
43-
<x:expect label="*Do Not* generate a NavPoint if $nav.in.ncx *is not* specified"/>
120+
<x:scenario label="When a nav TOC is matched in ncx.toc.gen mode...">
121+
<x:context mode="ncx.toc.gen">
122+
<nav data-type="toc"/>
123+
</x:context>
124+
125+
<x:scenario label="...with $nav.in.ncx enabled">
126+
<x:context>
127+
<x:param name="nav.in.ncx" select="1"/>
128+
</x:context>
129+
<x:expect label="Generate a navPoint">
130+
<ncx:navPoint id="...">...</ncx:navPoint>
131+
</x:expect>
132+
</x:scenario>
133+
134+
<x:scenario label="...with $nav.in.ncx disabled">
135+
<x:context>
136+
<x:param name="nav.in.ncx" select="0"/>
137+
</x:context>
138+
<x:expect label="*Do not* generate a navPoint"
139+
test="not(exists(ncx:navPoint))"/>
140+
</x:scenario>
44141
</x:scenario>
45142

46143
<x:scenario label="When generate.navpoint is called">
47-
<x:call/>
48-
<x:expect label="A NavPoint element should be generated with proper id"/>
49-
<x:expect label="A NavLabel element should be generated with properly formatted heading text"/>
50-
<x:expect label="A NavLabel's text content should include labels if $ncx.toc.include.labels is specified"/>
51-
<x:expect label="A NavLabel's text content *should not* include labels if $ncx.toc.include.labels *is not* specified"/>
52-
<x:expect label="A NavLabel's text content *should not* contain any inline elements"/>
53-
<x:expect label="A NavPoint element should contain a src attribute with the proper href"/>
144+
<x:call template="generate.navpoint">
145+
<x:param name="node">
146+
<section data-type="appendix">
147+
<h1>Tables of Crucial Data</h1>
148+
<p>Read me, please!</p>
149+
</section>
150+
</x:param>
151+
</x:call>
152+
<x:expect label="A navPoint element should be generated with proper id"
153+
test="count(ncx:navPoint[contains(@id, 'appendix')]) = 1"/>
154+
155+
<x:expect label="A navLabel element should be generated with properly formatted heading text"
156+
test="count(ncx:navPoint/ncx:navLabel[contains(., 'Tables of Crucial Data')]) = 1"/>
157+
158+
<x:scenario label="with $ncx.toc.include.label enabled">
159+
<x:call>
160+
<x:param name="ncx.toc.include.labels" select="1"/>
161+
</x:call>
162+
<!-- Note: the following value is dependent on the global params set in this xspec document -->
163+
<!-- If test fails, double-check expected value is in sync with these params -->
164+
<x:expect label="A navLabel's text content should include labels"
165+
test="count(ncx:navPoint/ncx:navLabel[contains(., 'A. ')]) = 1"/>
166+
</x:scenario>
167+
168+
<x:scenario label="with $ncx.toc.include.label disabled">
169+
<x:call>
170+
<x:param name="ncx.toc.include.labels" select="0"/>
171+
</x:call>
172+
<x:expect label="A navLabel's text content *should not* include labels"
173+
test="count(ncx:navPoint/ncx:navLabel[not(contains(., '. '))]) = 1"/>
174+
</x:scenario>
175+
176+
<x:scenario label="On a section with a title that contains inlines">
177+
<x:call>
178+
<x:param name="node">
179+
<section data-type="appendix">
180+
<h1>Tables of <em>Really</em> Crucial Data</h1>
181+
<p>Read me, please!</p>
182+
</section>
183+
</x:param>
184+
</x:call>
185+
<x:expect label="A navLabel's text content *should not* contain any inline elements"
186+
test="not(exists(ncx:navPoint/ncx:navLabel/ncx:text/*))"/>
187+
</x:scenario>
188+
189+
<!-- More robust testing here for src attribute value might be nice. -->
190+
<x:expect label="A navPoint element should contain a content element with a src attribute"
191+
test="exists(ncx:navPoint/ncx:content[@src])"/>
192+
54193
</x:scenario>
55-
</x:pending>
56194

57195
</x:description>

htmlbook-xsl/xspec/opf.xspec

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,12 +460,12 @@ UbuntuMono-Regular.otf
460460
<x:context mode="opf.spine.itemref">
461461
<nav data-type="toc"/>
462462
</x:context>
463-
<x:expect label="An itemref should be generated when nav.in.spine is enabled" test="count(/opf:itemref[contains(@idref, 'toc')]) = 1"/>
464-
<x:scenario label="with nav.in.spine disabled">
463+
<x:expect label="An itemref *should not* be generated by default" test="count(/opf:itemref) = 0"/>
464+
<x:scenario label="with nav.in.spine enabled">
465465
<x:context>
466-
<x:param name="nav.in.spine"/>
466+
<x:param name="nav.in.spine">1</x:param>
467467
</x:context>
468-
<x:expect label="An itemref *should not* be generated" test="count(/opf:itemref) = 0"/>
468+
<x:expect label="An itemref should be generated when nav.in.spine is enabled" test="count(/opf:itemref[contains(@idref, 'toc')]) = 1"/>
469469
</x:scenario>
470470
</x:scenario>
471471

0 commit comments

Comments
 (0)