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.
- data/.gemtest +0 -0
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Rakefile +12 -0
- data/epub-parser.gemspec +33 -0
- data/lib/epub/book.rb +37 -0
- data/lib/epub/content_document.rb +6 -0
- data/lib/epub/content_document/navigation.rb +80 -0
- data/lib/epub/ocf.rb +8 -0
- data/lib/epub/ocf/container.rb +22 -0
- data/lib/epub/ocf/encryption.rb +6 -0
- data/lib/epub/ocf/manifest.rb +6 -0
- data/lib/epub/ocf/metadata.rb +6 -0
- data/lib/epub/ocf/rights.rb +6 -0
- data/lib/epub/ocf/signatures.rb +6 -0
- data/lib/epub/parser.rb +46 -0
- data/lib/epub/parser/content_document.rb +58 -0
- data/lib/epub/parser/ocf.rb +59 -0
- data/lib/epub/parser/publication.rb +87 -0
- data/lib/epub/parser/version.rb +5 -0
- data/lib/epub/publication.rb +6 -0
- data/lib/epub/publication/package.rb +25 -0
- data/lib/epub/publication/package/bindings.rb +18 -0
- data/lib/epub/publication/package/guide.rb +11 -0
- data/lib/epub/publication/package/manifest.rb +44 -0
- data/lib/epub/publication/package/metadata.rb +17 -0
- data/lib/epub/publication/package/spine.rb +46 -0
- data/lib/epub/type.rb +7 -0
- data/schemas/epub-nav-30.rnc +10 -0
- data/schemas/epub-nav-30.sch +72 -0
- data/schemas/epub-xhtml-30.sch +377 -0
- data/schemas/ocf-container-30.rnc +16 -0
- data/test/fixtures/book.epub +0 -0
- data/test/fixtures/book/META-INF/container.xml +6 -0
- data/test/fixtures/book/OPS/nav.xhtml +26 -0
- 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
- data/test/fixtures/book/mimetype +1 -0
- data/test/helper.rb +9 -0
- data/test/publication/package/test_bindings.rb +15 -0
- data/test/publication/package/test_guide.rb +14 -0
- data/test/publication/package/test_manifest.rb +19 -0
- data/test/publication/package/test_metadata.rb +14 -0
- data/test/publication/package/test_spine.rb +15 -0
- data/test/test_parser.rb +52 -0
- data/test/test_parser_ocf.rb +22 -0
- data/test/test_parser_publication.rb +15 -0
- metadata +208 -0
@@ -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,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,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']) < 2">Multiple occurrences of
|
12
|
+
the 'page-list' nav element</assert>
|
13
|
+
<assert test="count(.//html:nav[@epub:type='landmarks']) < 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]) < 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)]) < 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>
|