epub-maker 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ module EPUB
2
+ module Maker
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0"?>
2
+ <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
3
+ <rootfiles>
4
+ <rootfile full-path="OPS/ルートファイル.opf" media-type="application/oebps-package+xml" />
5
+ </rootfiles>
6
+ </container>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0"?>
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
+ <head>
4
+ <title>Alternative Implementation of slideshow.xml</title>
5
+ </head>
6
+ <body>
7
+ <script type="text/javascript"></script>
8
+ </body>
9
+ </html>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0"?>
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
+ <head>
4
+ <title>Page 1</title>
5
+ </head>
6
+ <body>
7
+ </body>
8
+ </html>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0"?>
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
+ <head>
4
+ <title>Page 1</title>
5
+ </head>
6
+ <body>
7
+ <section id="section1">
8
+ </section>
9
+ <section id="section2">
10
+ </section>
11
+ </body>
12
+ </html>
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0"?>
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
3
+ <head>
4
+ <title>Table of Contents for Example Book</title>
5
+ </head>
6
+ <body>
7
+ <div>
8
+ <nav epub:type="toc" id="idid">
9
+ <hgroup>
10
+ <h2>Sub Navigation</h2>
11
+ <h1>Table of Contents</h1>
12
+ </hgroup>
13
+ <ol>
14
+ <li><a href="item-1.xhtml">一ページ目</a></li>
15
+ <li>
16
+ <span>二ページ目</span>
17
+ <ol>
18
+ <li><a href="item-2.xhtml#section1">第一節</a></li>
19
+ <li><a href="item-2.xhtml#section2">第二節</a></li>
20
+ </ol>
21
+ </li>
22
+ </ol>
23
+ </nav>
24
+ </div>
25
+ </body>
26
+ </html>
File without changes
@@ -0,0 +1,91 @@
1
+ <?xml version="1.0"?>
2
+ <package version="3.0"
3
+ unique-identifier="pub-id"
4
+ xmlns="http://www.idpf.org/2007/opf">
5
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
6
+ <dc:identifier id="pub-id">da265185-8da8-462d-a146-17dd388f61fc</dc:identifier>
7
+
8
+ <dc:title id="t1" xml:lang="fr">Mon premier guide de cuisson, un Mémoire</dc:title>
9
+ <meta refines="#t1" property="title-type">main</meta>
10
+ <meta refines="#t1" property="display-seq">2</meta>
11
+
12
+ <dc:title id="t2">The Great Cookbooks of the World</dc:title>
13
+ <meta refines="#t2" property="title-type">collection</meta>
14
+ <meta refines="#t2" property="display-seq">1</meta>
15
+
16
+ <dc:title id="t3">The New French Cuisine Masters</dc:title>
17
+ <meta refines="#t3" property="title-type">collection</meta>
18
+ <meta refines="#t3" property="group-position">2</meta>
19
+ <meta refines="#t3" property="display-seq">3</meta>
20
+
21
+ <dc:title id="t4">Special Anniversary Edition</dc:title>
22
+ <meta refines="#t4" property="title-type">edition</meta>
23
+ <meta refines="#t4" property="display-seq">4</meta>
24
+
25
+ <dc:title id="t5">The Great Cookbooks of the World:
26
+ Mon premier guide de cuisson, un Mémoire.
27
+ The New French Cuisine Masters, Volume Two.
28
+ Special Anniversary Edition</dc:title>
29
+ <meta refines="#t5" property="title-type">extended</meta>
30
+
31
+ <dc:language>ja</dc:language>
32
+ <meta property="dcterms:modified">2012-02-03T12:00:00Z</meta>
33
+
34
+ <dc:creator id="creator01">Lewis Carroll</dc:creator>
35
+ <meta refines="#creator01" property="role" scheme="marc:relators">aut</meta>
36
+ <meta refines="#creator01" property="display-seq">1</meta>
37
+
38
+ <dc:creator id="creator02">John Tenniel</dc:creator>
39
+ <meta refines="#creator02" property="role" scheme="marc:relators">ill</meta>
40
+ <meta refines="#creator02" property="display-seq">2</meta>
41
+
42
+
43
+ <link rel="onix-record" href="http://example.org/onix/12389347" refines="#pub-id"/>
44
+ <link rel="xmp-record" href="http://example.org/xmp/12389347"/>
45
+ </metadata>
46
+ <manifest id="manifest-id">
47
+ <item id="nav"
48
+ href="nav.xhtml"
49
+ media-type="application/xhtml+xml"
50
+ properties="nav"/>
51
+ <item id="cover"
52
+ href="表紙.xhtml"
53
+ media-type="application/xhtml+xml"/>
54
+ <item id="manifest-item-1"
55
+ href="item-1.xhtml"
56
+ media-type="application/pdf"
57
+ properties="property1 property2 property3"
58
+ fallback="manifest-item-2"/>
59
+ <item id="impl"
60
+ href="impl.xhtml"
61
+ media-type="application/xhtml+xml"
62
+ properties="scripted"/>
63
+ <item id="slideshow"
64
+ href="slideshow.xml"
65
+ media-type="application/x-demo-slideshow"/>
66
+ <item id="manifest-item-2"
67
+ href="item-2.xhtml"
68
+ media-type="application/pdf"
69
+ fallback="manifest-item-fallback"/>
70
+ <item id="manifest-item-fallback"
71
+ href="fallback.xhtml"
72
+ media-type="image/svg+xml"
73
+ fallback="manifest-item-fallback2"/>
74
+ <item id="manifest-item-fallback2"
75
+ href="fallback2.xhtml"
76
+ media-type="application/xhtml+xml"/>
77
+ </manifest>
78
+ <spine id="spine-id">
79
+ <itemref idref="cover" linear="no"/>
80
+ <itemref idref="nav"/>
81
+ <itemref idref="manifest-item-1"/>
82
+ <itemref idref="manifest-item-2"/>
83
+ </spine>
84
+ <guide>
85
+ <reference type="cover" href="表紙.xhtml#start" title="カバー"/>
86
+ </guide>
87
+ <bindings>
88
+ <mediaType handler="impl"
89
+ media-type="application/x-demo-slideshow"/>
90
+ </bindings>
91
+ </package>
@@ -0,0 +1,17 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/test|deps/'
4
+ end
5
+
6
+ require 'test/unit/full'
7
+ require 'open3'
8
+ require 'shellwords'
9
+ class Test::Unit::TestCase
10
+ def assert_valid_epub(file)
11
+ jar = File.join(ENV['GEM_HOME'], 'gems', 'epubcheck-3.0.0', 'lib', 'epubcheck-3.0', 'epubcheck-3.0.jar')
12
+ stderr, status = Open3.capture2e "java -jar #{jar.shellescape} #{file.shellescape}"
13
+ assert_true (status.exitstatus == 0 or stderr !~ /^ERROR: /), stderr
14
+ end
15
+ end
16
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
17
+ require 'epub'
@@ -0,0 +1,24 @@
1
+ require_relative 'helper'
2
+ require 'epub/maker/rake/make_task'
3
+
4
+ EPUB::Maker::Rake::MakeTask.new do |task|
5
+ # task.title = 'Sample eBook'
6
+ # task.language = 'ja'
7
+ # task.contributors = ['KITAITI Makoto']
8
+
9
+ dir = Pathname(__dir__) + 'fixtures' + 'book'
10
+ Pathname.glob("#{dir}/OPS/*.xhtml").each do |path|
11
+ task.files << path.to_path
12
+ task.map[path.to_path] = path.relative_path_from(dir).to_path
13
+ end
14
+
15
+ require 'pp'
16
+ pp task.files
17
+ pp task.map
18
+
19
+ task.base_dir = File.join(__dir__, 'fixtures', 'book')
20
+ task.files = FileList["#{task.base_dir}/OPS/*"].sort
21
+
22
+ pp task.build_map
23
+
24
+ end
@@ -0,0 +1,10 @@
1
+
2
+
3
+ default namespace = "http://www.w3.org/1999/xhtml"
4
+ namespace epub = "http://www.idpf.org/2007/ops"
5
+
6
+ include "epub-xhtml-30.rnc" {
7
+ html5.nav.content = html5.headings.class?, html5.ol
8
+ html5.oli.content = html5.a.phrasing | ((html5.a.phrasing | html5.span), html5.ol)
9
+ }
10
+
@@ -0,0 +1,72 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <schema xmlns="http://purl.oclc.org/dsdl/schematron">
3
+
4
+ <ns uri="http://www.w3.org/1999/xhtml" prefix="html"/>
5
+ <ns uri="http://www.idpf.org/2007/ops" prefix="epub"/>
6
+
7
+ <pattern id="nav-ocurrence">
8
+ <rule context="html:body">
9
+ <assert test="count(.//html:nav[@epub:type='toc']) = 1">Exactly one 'toc' nav element
10
+ must be present</assert>
11
+ <assert test="count(.//html:nav[@epub:type='page-list']) &lt; 2">Multiple occurrences of
12
+ the 'page-list' nav element</assert>
13
+ <assert test="count(.//html:nav[@epub:type='landmarks']) &lt; 2">Multiple occurrences of
14
+ the 'landmarks' nav element</assert>
15
+ </rule>
16
+ </pattern>
17
+
18
+ <pattern id="span-no-sublist">
19
+ <rule context="html:body//html:nav//html:span">
20
+ <assert test="count(.//ol) = 0"> The span element must only be used as heading for flat
21
+ sublists (not hierarchical navigation structures) </assert>
22
+ </rule>
23
+ </pattern>
24
+
25
+ <pattern id="landmarks">
26
+ <rule context="html:nav[@epub:type='landmarks']//html:ol//html:a">
27
+ <assert test="@epub:type">Missing epub:type attribute on anchor inside 'landmarks' nav
28
+ element</assert>
29
+ </rule>
30
+ </pattern>
31
+
32
+ <pattern id="link-labels">
33
+ <rule context="html:nav//html:ol//html:a">
34
+ <assert test="string-length(normalize-space(string(.))) > 0">Anchors within nav elements
35
+ must contain text</assert>
36
+ </rule>
37
+ </pattern>
38
+
39
+ <pattern id="span-labels">
40
+ <rule context="html:nav//html:ol//html:span">
41
+ <assert test="string-length(normalize-space(string(.))) > 0">Spans within nav elements
42
+ must contain text</assert>
43
+ </rule>
44
+ </pattern>
45
+
46
+ <pattern id="req-heading">
47
+ <rule
48
+ context="html:nav[not(@epub:type = 'toc') and not (@epub:type = 'page-list') and not (@epub:type = 'landmarks')]">
49
+ <let name="fc" value="local-name(./*[1])"/>
50
+ <assert test="(starts-with($fc,'h') and string-length($fc) = 2) or ($fc = 'hgroup')">nav
51
+ elements other than 'toc', 'page-list' and 'landmarks' must contain a heading as the
52
+ first child</assert>
53
+ </rule>
54
+ </pattern>
55
+
56
+ <pattern id="heading-content">
57
+ <rule context="html:h1|html:h2|html:h3|html:h4|html:h5|html:h6|html:hgroup">
58
+ <assert test="string-length(normalize-space(string(.))) > 0">Heading elements must
59
+ contain text</assert>
60
+ </rule>
61
+ </pattern>
62
+
63
+
64
+ <!-- warnings mode <pattern id="page-list-flat">
65
+ <rule context="html:body//html:nav[@epub:type='page-list']">
66
+ <assert test="count(.//html:ol) = 1">The page-list navigation structure should be a
67
+ list, not a nested hierarchy</assert>
68
+ </rule>
69
+ </pattern>
70
+ -->
71
+
72
+ </schema>
@@ -0,0 +1,377 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
3
+
4
+ <ns uri="http://www.w3.org/1999/xhtml" prefix="h"/>
5
+ <ns uri="http://www.idpf.org/2007/ops" prefix="epub"/>
6
+ <ns uri="http://www.w3.org/1998/Math/MathML" prefix="math"/>
7
+ <ns uri="http://www.w3.org/2001/10/synthesis" prefix="ssml"/>
8
+ <ns uri="http://www.w3.org/2001/xml-events" prefix="ev"/>
9
+ <ns uri="http://www.w3.org/2000/svg" prefix="svg" />
10
+
11
+ <let name="id-set" value="//*[@id]"/>
12
+
13
+ <pattern id="ancestor-area-map" is-a="required-ancestor">
14
+ <param name="descendant" value="h:area"/>
15
+ <param name="ancestor" value="h:map"/>
16
+ </pattern>
17
+
18
+ <pattern id="ancestor-imgismap-ahref" is-a="required-ancestor">
19
+ <param name="descendant" value="h:img[@ismap]"/>
20
+ <param name="ancestor" value="h:a[@href]"/>
21
+ </pattern>
22
+
23
+ <pattern id="descendant-a-interactive" is-a="no-interactive-content-descendants">
24
+ <param name="ancestor" value="h:a"/>
25
+ </pattern>
26
+
27
+ <pattern id="descendant-button-interactive" is-a="no-interactive-content-descendants">
28
+ <param name="ancestor" value="h:button"/>
29
+ </pattern>
30
+
31
+ <pattern id="descendant-audio-audio" is-a="disallowed-descendants">
32
+ <param name="ancestor" value="h:audio"/>
33
+ <param name="descendant" value="h:audio"/>
34
+ </pattern>
35
+
36
+ <pattern id="descendant-audio-video" is-a="disallowed-descendants">
37
+ <param name="ancestor" value="h:audio"/>
38
+ <param name="descendant" value="h:video"/>
39
+ </pattern>
40
+
41
+ <pattern id="descendant-video-video" is-a="disallowed-descendants">
42
+ <param name="ancestor" value="h:video"/>
43
+ <param name="descendant" value="h:video"/>
44
+ </pattern>
45
+
46
+ <pattern id="descendant-video-audio" is-a="disallowed-descendants">
47
+ <param name="ancestor" value="h:video"/>
48
+ <param name="descendant" value="h:audio"/>
49
+ </pattern>
50
+
51
+ <pattern id="descendant-address-address" is-a="disallowed-descendants">
52
+ <param name="ancestor" value="h:address"/>
53
+ <param name="descendant" value="h:address"/>
54
+ </pattern>
55
+
56
+ <pattern id="descendant-address-header" is-a="disallowed-descendants">
57
+ <param name="ancestor" value="h:address"/>
58
+ <param name="descendant" value="h:header"/>
59
+ </pattern>
60
+
61
+ <pattern id="descendant-address-footer" is-a="disallowed-descendants">
62
+ <param name="ancestor" value="h:address"/>
63
+ <param name="descendant" value="h:footer"/>
64
+ </pattern>
65
+
66
+ <pattern id="descendant-form-form" is-a="disallowed-descendants">
67
+ <param name="ancestor" value="h:form"/>
68
+ <param name="descendant" value="h:form"/>
69
+ </pattern>
70
+
71
+ <pattern id="descendant-progress-progress" is-a="disallowed-descendants">
72
+ <param name="ancestor" value="h:progress"/>
73
+ <param name="descendant" value="h:progress"/>
74
+ </pattern>
75
+
76
+ <pattern id="descendant-meter-meter" is-a="disallowed-descendants">
77
+ <param name="ancestor" value="h:meter"/>
78
+ <param name="descendant" value="h:meter"/>
79
+ </pattern>
80
+
81
+ <pattern id="descendant-dfn-dfn" is-a="disallowed-descendants">
82
+ <param name="ancestor" value="h:dfn"/>
83
+ <param name="descendant" value="h:dfn"/>
84
+ </pattern>
85
+
86
+ <pattern id="descendant-time-time" is-a="disallowed-descendants">
87
+ <param name="ancestor" value="h:time"/>
88
+ <param name="descendant" value="h:time"/>
89
+ </pattern>
90
+
91
+ <pattern id="descendant-caption-table" is-a="disallowed-descendants">
92
+ <param name="ancestor" value="h:caption"/>
93
+ <param name="descendant" value="h:table"/>
94
+ </pattern>
95
+
96
+ <pattern id="descendant-header-header" is-a="disallowed-descendants">
97
+ <param name="ancestor" value="h:header"/>
98
+ <param name="descendant" value="h:header"/>
99
+ </pattern>
100
+
101
+ <pattern id="descendant-header-footer" is-a="disallowed-descendants">
102
+ <param name="ancestor" value="h:header"/>
103
+ <param name="descendant" value="h:footer"/>
104
+ </pattern>
105
+
106
+ <pattern id="descendant-footer-footer" is-a="disallowed-descendants">
107
+ <param name="ancestor" value="h:footer"/>
108
+ <param name="descendant" value="h:footer"/>
109
+ </pattern>
110
+
111
+ <pattern id="descendant-footer-header" is-a="disallowed-descendants">
112
+ <param name="ancestor" value="h:footer"/>
113
+ <param name="descendant" value="h:header"/>
114
+ </pattern>
115
+
116
+ <pattern id="descendant-label-label" is-a="disallowed-descendants">
117
+ <param name="ancestor" value="h:label"/>
118
+ <param name="descendant" value="h:label"/>
119
+ </pattern>
120
+
121
+ <pattern id="descendant-annotation-xml-math" is-a="disallowed-descendants">
122
+ <param name="ancestor" value="math:annotation-xml[@encoding='application/xhtml+xml' and @name='alternate-representation']"/>
123
+ <param name="descendant" value="math:*"/>
124
+ </pattern>
125
+
126
+ <pattern id="descendant-svgtitle-svg" is-a="disallowed-descendants">
127
+ <param name="ancestor" value="svg:title"/>
128
+ <param name="descendant" value="svg:*"/>
129
+ </pattern>
130
+
131
+ <pattern id="bdo-dir" is-a="required-attr">
132
+ <param name="elem" value="h:bdo"/>
133
+ <param name="attr" value="dir"/>
134
+ </pattern>
135
+
136
+ <pattern id="idrefs-aria-describedby" is-a="idrefs-any">
137
+ <param name="element" value="*"/>
138
+ <param name="idrefs-attr-name" value="aria-describedby"/>
139
+ </pattern>
140
+
141
+ <pattern id="idrefs-output-for" is-a="idrefs-any">
142
+ <param name="element" value="h:output"/>
143
+ <param name="idrefs-attr-name" value="for"/>
144
+ </pattern>
145
+
146
+ <pattern id="idrefs-aria-flowto" is-a="idrefs-any">
147
+ <param name="element" value="*"/>
148
+ <param name="idrefs-attr-name" value="aria-flowto"/>
149
+ </pattern>
150
+
151
+ <pattern id="idrefs-aria-labelledby" is-a="idrefs-any">
152
+ <param name="element" value="*"/>
153
+ <param name="idrefs-attr-name" value="aria-labelledby"/>
154
+ </pattern>
155
+
156
+ <pattern id="idrefs-aria-owns" is-a="idrefs-any">
157
+ <param name="element" value="*"/>
158
+ <param name="idrefs-attr-name" value="aria-owns"/>
159
+ </pattern>
160
+
161
+ <pattern id="idrefs-aria-controls" is-a="idrefs-any">
162
+ <param name="element" value="*"/>
163
+ <param name="idrefs-attr-name" value="aria-controls"/>
164
+ </pattern>
165
+
166
+ <pattern id="idref-mathml-xref" is-a="idref-any">
167
+ <param name="element" value="math:*"/>
168
+ <param name="idref-attr-name" value="xref"/>
169
+ </pattern>
170
+
171
+ <pattern id="idref-mathml-indenttarget" is-a="idref-any">
172
+ <param name="element" value="math:*"/>
173
+ <param name="idref-attr-name" value="indenttarget"/>
174
+ </pattern>
175
+
176
+ <pattern id="idref-contextmenu" is-a="idref-named">
177
+ <param name="element" value="h:*"/>
178
+ <param name="idref-attr-name" value="contextmenu"/>
179
+ <param name="target-name" value="h:menu"/>
180
+ </pattern>
181
+
182
+ <pattern id="idref-input-list" is-a="idref-named">
183
+ <param name="element" value="h:input"/>
184
+ <param name="idref-attr-name" value="list"/>
185
+ <param name="target-name" value="h:datalist"/>
186
+ </pattern>
187
+
188
+ <pattern id="idref-forms-form" is-a="idref-named">
189
+ <param name="element" value="h:*"/>
190
+ <param name="idref-attr-name" value="form"/>
191
+ <param name="target-name" value="h:form"/>
192
+ </pattern>
193
+
194
+ <pattern id="idref-aria-activedescendant">
195
+ <rule context="*[@aria-activedescendant]">
196
+ <assert test="descendant::*[@id = current()/@aria-activedescendant]"
197
+ >The aria-activedescendant attribute must refer to a descendant element.</assert>
198
+ </rule>
199
+ </pattern>
200
+
201
+ <pattern id="idref-label-for">
202
+ <rule context="h:label[@for]">
203
+ <assert
204
+ test="some $elem in $id-set satisfies $elem/@id eq current()/@for and
205
+ (local-name($elem) eq 'button'
206
+ or (local-name($elem) eq 'input' and not($elem/@type='hidden'))
207
+ or local-name($elem) eq 'keygen'
208
+ or local-name($elem) eq 'meter'
209
+ or local-name($elem) eq 'output'
210
+ or local-name($elem) eq 'progress'
211
+ or local-name($elem) eq 'select'
212
+ or local-name($elem) eq 'textarea')"
213
+ >The for attribute does not refer to an allowed target element (expecting: button|keygen|meter|output|progress|select|textarea|input[not(@type='hidden')]).</assert>
214
+ </rule>
215
+ </pattern>
216
+
217
+ <pattern id="idrefs-headers">
218
+ <rule context="h:*[@headers]">
219
+ <let name="table" value="ancestor::h:table"/>
220
+ <assert test="every $idref in tokenize(@headers, '\s+') satisfies (some $elem in $table//h:th satisfies ($elem/@id eq $idref))"
221
+ >The headers attribute must refer to th elements in the same table.</assert>
222
+ </rule>
223
+ </pattern>
224
+
225
+ <pattern id="idref-trigger-observer" is-a="idref-any">
226
+ <param name="element" value="epub:trigger"/>
227
+ <param name="idref-attr-name" value="ev:observer"/>
228
+ </pattern>
229
+
230
+ <pattern id="idref-trigger-ref" is-a="idref-any">
231
+ <param name="element" value="epub:trigger"/>
232
+ <param name="idref-attr-name" value="ref"/>
233
+ </pattern>
234
+
235
+ <pattern id="map.name" >
236
+ <rule context='h:map[@name]'>
237
+ <let name="name-set" value="//h:map[@name]"/>
238
+ <assert test="count($name-set[@name = current()/@name]) = 1">Duplicate map name '<value-of
239
+ select="current()/@name"/>'</assert>
240
+ </rule>
241
+ </pattern>
242
+
243
+ <pattern id="map.id" >
244
+ <rule context='h:map[@id and @name]'>
245
+ <assert test='@id = @name'
246
+ >The id attribute on the map element must have the same value as the name attribute.</assert>
247
+ </rule>
248
+ </pattern>
249
+
250
+ <pattern id='lang-xmllang'>
251
+ <rule context='h:*[@lang and @xml:lang]'>
252
+ <assert test="lower-case(@xml:lang) = lower-case(@lang)"
253
+ >The lang and xml:lang attributes must have the same value.</assert>
254
+ </rule>
255
+ </pattern>
256
+
257
+ <pattern id="id-unique">
258
+ <rule context="*[@id]">
259
+ <assert test="count($id-set[@id = current()/@id]) = 1">Duplicate ID '<value-of
260
+ select="current()/@id"/>'</assert>
261
+ </rule>
262
+ </pattern>
263
+
264
+ <pattern id="select-multiple">
265
+ <rule context="h:select[not(@multiple)]">
266
+ <report test='count(descendant::h:option[@selected]) > 1'
267
+ >A select element whose multiple attribute is not specified must not have more than one descendant option element with its selected attribute set.</report>
268
+ </rule>
269
+ </pattern>
270
+
271
+ <pattern id="track">
272
+ <rule context="h:track">
273
+ <report test="@label and normalize-space(@label) = ''"
274
+ >The track element label attribute value must not be the empty string.</report>
275
+ <report test="@default and preceding-sibling::h:track[@default]"
276
+ >There must not be more than one track child of a media element element with the default attribute specified.</report>
277
+ </rule>
278
+ </pattern>
279
+
280
+ <pattern id="ssml-ph">
281
+ <rule context="*[@ssml:ph]">
282
+ <report test="ancestor::*[@ssml:ph]"
283
+ >The ssml:ph attribute must not be specified on a descendant of an element that also carries this attribute.</report>
284
+ </rule>
285
+ </pattern>
286
+
287
+ <pattern id="style-scoped">
288
+ <rule context="h:style[ancestor::h:body]">
289
+ <assert test="every $elem in preceding-sibling::* satisfies local-name($elem) eq 'style'"
290
+ >The scoped style element must occur before any other flow content other than other style elements and inter-element whitespace.</assert>
291
+ </rule>
292
+ </pattern>
293
+
294
+ <pattern id="link-sizes">
295
+ <rule context="h:link[@sizes]">
296
+ <assert test="@rel='icon'"
297
+ >The sizes attribute must not be specified on link elements that do not have a rel attribute that specifies the icon keyword.</assert>
298
+ </rule>
299
+ </pattern>
300
+
301
+ <pattern id="meta-charset">
302
+ <rule context="h:meta[@charset]">
303
+ <assert test="count(preceding-sibling::h:meta[@charset]) = 0"
304
+ >There must not be more than one meta element with a charset attribute per document.</assert>
305
+ </rule>
306
+ </pattern>
307
+
308
+ <pattern id="article-pubdate">
309
+ <rule context="h:article[h:time]">
310
+ <assert test="count(./h:time[@pubdate]) &lt; 2"
311
+ >For each article element, there must be no more than one time element child with a pubdate attribute</assert>
312
+ </rule>
313
+ </pattern>
314
+
315
+ <pattern id="document-pubdate">
316
+ <rule context="h:time[not (ancestor::h:article)]">
317
+ <assert test="count(//h:time[@pubdate and not (ancestor::h:article)]) &lt; 2"
318
+ >For each Document, there must be no more than one time element with a pubdate
319
+ attribute that does not have an ancestor article element.</assert>
320
+ </rule>
321
+ </pattern>
322
+
323
+ <pattern abstract="true" id="idref-any">
324
+ <rule context="$element[@$idref-attr-name]">
325
+ <assert test="some $elem in $id-set satisfies $elem/@id eq current()/@$idref-attr-name"
326
+ >The <name path="@$idref-attr-name"/> attribute must refer to an element in the same document (the ID '<value-of
327
+ select="current()/@$idref-attr-name"/>' does not exist).</assert>
328
+ </rule>
329
+ </pattern>
330
+
331
+ <pattern abstract="true" id="idrefs-any">
332
+ <rule context="$element[@$idrefs-attr-name]">
333
+ <assert test="every $idref in tokenize(@$idrefs-attr-name,'\s+') satisfies (some $elem in $id-set satisfies ($elem/@id eq $idref))"
334
+ >The <name path="@$idrefs-attr-name"/> attribute must refer to elements in the same document (target ID missing)</assert>
335
+ </rule>
336
+ </pattern>
337
+
338
+ <pattern abstract="true" id="idref-named">
339
+ <rule context="$element[@$idref-attr-name]">
340
+ <assert test="//$target-name[@id = current()/@$idref-attr-name]">The <name
341
+ path="@$idref-attr-name"/> attribute does not refer to an allowed target element (expecting: <value-of
342
+ select="replace('$target-name','h:','')"/>).</assert>
343
+ </rule>
344
+ </pattern>
345
+
346
+ <pattern abstract="true" id="required-attr">
347
+ <rule context="$elem">
348
+ <assert test="@$attr"
349
+ >The <name/> element must have a <value-of select="'$attr'"/> attribute.</assert>
350
+ </rule>
351
+ </pattern>
352
+
353
+ <pattern abstract="true" id="disallowed-descendants">
354
+ <rule context="$descendant">
355
+ <report test="ancestor::$ancestor"
356
+ >The <name/> element must not appear inside <value-of select="local-name(ancestor::$ancestor)"/> elements.</report>
357
+ </rule>
358
+ </pattern>
359
+
360
+ <pattern abstract="true" id="required-ancestor">
361
+ <rule context='$descendant'>
362
+ <assert test='ancestor::$ancestor'
363
+ >The <value-of select="replace('$descendant','h:','')"/> element must have an ancestor <value-of select="replace('$ancestor','h:','')"/> element.</assert>
364
+ </rule>
365
+ </pattern>
366
+
367
+ <pattern abstract="true" id="no-interactive-content-descendants">
368
+ <rule context="h:a|h:audio[@controls]|h:button|h:details|h:embed|h:iframe|h:img[@usemap]|h:input[not(@type='hidden')]
369
+ |h:keygen|h:label|h:menu[@type='toolbar']|h:object[@usemap]|h:select|h:textarea|h:video[@controls]">
370
+ <report test="ancestor::$ancestor"
371
+ >The <name/> element must not appear inside <value-of select="local-name(ancestor::$ancestor)"/> elements.</report>
372
+ </rule>
373
+ </pattern>
374
+
375
+ <include href="./mod/epub-svg11-re.sch"/>
376
+
377
+ </schema>