epub-parser 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.
Files changed (47) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +12 -0
  5. data/epub-parser.gemspec +33 -0
  6. data/lib/epub/book.rb +37 -0
  7. data/lib/epub/content_document.rb +6 -0
  8. data/lib/epub/content_document/navigation.rb +80 -0
  9. data/lib/epub/ocf.rb +8 -0
  10. data/lib/epub/ocf/container.rb +22 -0
  11. data/lib/epub/ocf/encryption.rb +6 -0
  12. data/lib/epub/ocf/manifest.rb +6 -0
  13. data/lib/epub/ocf/metadata.rb +6 -0
  14. data/lib/epub/ocf/rights.rb +6 -0
  15. data/lib/epub/ocf/signatures.rb +6 -0
  16. data/lib/epub/parser.rb +46 -0
  17. data/lib/epub/parser/content_document.rb +58 -0
  18. data/lib/epub/parser/ocf.rb +59 -0
  19. data/lib/epub/parser/publication.rb +87 -0
  20. data/lib/epub/parser/version.rb +5 -0
  21. data/lib/epub/publication.rb +6 -0
  22. data/lib/epub/publication/package.rb +25 -0
  23. data/lib/epub/publication/package/bindings.rb +18 -0
  24. data/lib/epub/publication/package/guide.rb +11 -0
  25. data/lib/epub/publication/package/manifest.rb +44 -0
  26. data/lib/epub/publication/package/metadata.rb +17 -0
  27. data/lib/epub/publication/package/spine.rb +46 -0
  28. data/lib/epub/type.rb +7 -0
  29. data/schemas/epub-nav-30.rnc +10 -0
  30. data/schemas/epub-nav-30.sch +72 -0
  31. data/schemas/epub-xhtml-30.sch +377 -0
  32. data/schemas/ocf-container-30.rnc +16 -0
  33. data/test/fixtures/book.epub +0 -0
  34. data/test/fixtures/book/META-INF/container.xml +6 -0
  35. data/test/fixtures/book/OPS/nav.xhtml +26 -0
  36. data/test/fixtures/book/OPS//343/203/253/343/203/274/343/203/210/343/203/225/343/202/241/343/202/244/343/203/253.opf +28 -0
  37. data/test/fixtures/book/mimetype +1 -0
  38. data/test/helper.rb +9 -0
  39. data/test/publication/package/test_bindings.rb +15 -0
  40. data/test/publication/package/test_guide.rb +14 -0
  41. data/test/publication/package/test_manifest.rb +19 -0
  42. data/test/publication/package/test_metadata.rb +14 -0
  43. data/test/publication/package/test_spine.rb +15 -0
  44. data/test/test_parser.rb +52 -0
  45. data/test/test_parser_ocf.rb +22 -0
  46. data/test/test_parser_publication.rb +15 -0
  47. metadata +208 -0
@@ -0,0 +1,5 @@
1
+ module EPUB
2
+ class Parser
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'epub/publication/package'
2
+
3
+ module EPUB
4
+ module Publication
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ %w[ metadata manifest spine guide ].each { |f| require "epub/publication/package/#{f}" }
2
+
3
+ module EPUB
4
+ module Publication
5
+ class Package
6
+ attr_accessor :version, :unique_identifier, :prefix, :xml_lang, :dir, :id
7
+ attr_reader :metadata, :manifest, :spine
8
+ alias lang xml_lang
9
+ alias lang= xml_lang=
10
+
11
+ def metadata=(metadata)
12
+ end
13
+
14
+ def manifest=(manifest)
15
+ manifest.package = self
16
+ @manifest = manifest
17
+ end
18
+
19
+ def spine=(spine)
20
+ spine.package = self
21
+ @spine = spine
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module EPUB
2
+ module Publication
3
+ class Package
4
+ class Bindings
5
+ attr_accessor :media_types
6
+
7
+ def <<(media_type)
8
+ @media_types ||= []
9
+ @media_types << media_type
10
+ end
11
+
12
+ class MediaType
13
+ attr_accessor :media_type, :handler
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ # This class is deprecated
2
+ # See OPF2 for specification
3
+
4
+ module EPUB
5
+ module Publication
6
+ class Package
7
+ class Guide
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ require 'enumerabler'
2
+
3
+ module EPUB
4
+ module Publication
5
+ class Package
6
+ class Manifest
7
+ attr_accessor :package,
8
+ :id
9
+ attr_reader :items
10
+
11
+ # syntax sugar for #items.<<
12
+ def <<(item)
13
+ @items ||= []
14
+ item.manifest = self
15
+ @items << item
16
+ end
17
+
18
+ # syntax sugar
19
+ def navs
20
+ items.selector {|i| i.properties.include? 'nav'}
21
+ end
22
+
23
+ def nav
24
+ navs.first
25
+ end
26
+
27
+ def [](item_id)
28
+ items.selector {|item| item.id == item_id}.first
29
+ end
30
+
31
+ class Item
32
+ attr_accessor :manifest,
33
+ :id, :href, :media_type, :fallback, :properties, :media_overlay
34
+
35
+ alias path href
36
+
37
+ def to_s
38
+ href.to_s
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,17 @@
1
+ module EPUB
2
+ module Publication
3
+ class Package
4
+ class Metadata
5
+ elems = [:identifiers, :titles, :languages] +
6
+ [:contributers, :coverages, :creators, :dates, :descriptions, :formats, :publishers,
7
+ :relations, :rigths, :sources, :subjects, :types]
8
+ attr_accessor *(elems.collect {|elem| "dc_#{elem}"})
9
+ elems.each do |elem|
10
+ alias_method elem, "dc_#{elem}"
11
+ alias_method "#{elem}=", "dc_#{elem}="
12
+ end
13
+ attr_accessor :metas, :links
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,46 @@
1
+ module EPUB
2
+ module Publication
3
+ class Package
4
+ class Spine
5
+ attr_accessor :package,
6
+ :id, :toc, :page_progression_direction
7
+ attr_reader :itemrefs
8
+
9
+ def <<(itemref)
10
+ @itemrefs ||= []
11
+ itemref.spine = self
12
+ @itemrefs << itemref
13
+ end
14
+
15
+ # @yield [itemref]
16
+ # @yieldparam [Itemref] itemref
17
+ # @yieldreturn [Object] returns the last value of block
18
+ # @return [Object, Enumerator]
19
+ # returns the last value of block when block given, Enumerator when not
20
+ def each_itemref
21
+ if block_given?
22
+ itemrefs.each {|itemref| yield itemref}
23
+ else
24
+ enum_for :each_itemref
25
+ end
26
+ end
27
+
28
+ # @return [Enumerator] Enumerator which yeilds {Manifest::Item}
29
+ # referred by each of {#itemrefs}
30
+ def items
31
+ itemrefs.collector {|itemref| itemref.item}
32
+ end
33
+
34
+ class Itemref
35
+ attr_accessor :spine,
36
+ :idref, :linear, :id, :properties
37
+
38
+ # @return [Package::Manifest::Item] item referred by this object
39
+ def item
40
+ @item ||= @spine.package.manifest[idref]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
data/lib/epub/type.rb ADDED
@@ -0,0 +1,7 @@
1
+ module EPUB
2
+ module Type
3
+ TOC = :toc
4
+ PAGE_LIST = :page_list
5
+ LANDMARKS = :landmarks
6
+ end
7
+ 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>