gepub 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/.travis.yml +6 -0
- data/README.rdoc +9 -55
- data/bin/gepuber +11 -6
- data/examples/generate_example.rb +52 -0
- data/examples/image1.jpg +0 -0
- data/gepub.gemspec +3 -4
- data/lib/gepub/book.rb +154 -176
- data/lib/gepub/gepuber.rb +6 -2
- data/lib/gepub/item.rb +66 -7
- data/lib/gepub/manifest.rb +78 -0
- data/lib/gepub/meta.rb +119 -0
- data/lib/gepub/metadata.rb +230 -0
- data/lib/gepub/package.rb +232 -0
- data/lib/gepub/spine.rb +112 -0
- data/lib/gepub/version.rb +1 -1
- data/lib/gepub/xml_util.rb +25 -0
- data/lib/gepub.rb +16 -0
- data/spec/example_spec.rb +53 -0
- data/spec/fixtures/epubcheck-3.0b4/COPYING.txt +19 -0
- data/spec/fixtures/epubcheck-3.0b4/README.txt +61 -0
- data/spec/fixtures/epubcheck-3.0b4/epubcheck-3.0b4.jar +0 -0
- data/spec/fixtures/epubcheck-3.0b4/jing_license.txt +12 -0
- data/spec/fixtures/epubcheck-3.0b4/lib/commons-compress-1.2.jar +0 -0
- data/spec/fixtures/epubcheck-3.0b4/lib/cssparser-0.9.6.jar +0 -0
- data/spec/fixtures/epubcheck-3.0b4/lib/jing.jar +0 -0
- data/spec/fixtures/epubcheck-3.0b4/lib/sac-1.3.jar +0 -0
- data/spec/fixtures/epubcheck-3.0b4/lib/saxon9he.jar +0 -0
- data/spec/fixtures/testdata/image1.jpg +0 -0
- data/spec/fixtures/testdata/test.opf +60 -0
- data/spec/gepub_spec.rb +57 -17
- data/spec/gepuber_spec.rb +8 -8
- data/spec/manifest_spec.rb +36 -0
- data/spec/metadata_spec.rb +170 -0
- data/spec/package_spec.rb +98 -0
- data/spec/spine_spec.rb +41 -0
- metadata +53 -23
- data/examples/example.rb +0 -49
data/lib/gepub/item.rb
CHANGED
@@ -1,21 +1,76 @@
|
|
1
1
|
module GEPUB
|
2
2
|
class Item
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :content
|
4
|
+
def self.create(parent, attributes = {})
|
5
|
+
Item.new(attributes['id'], attributes['href'], attributes['media-type'], parent,
|
6
|
+
attributes.reject { |k,v| ['id','href','media-type'].member?(k) })
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(itemid, itemhref, itemmediatype = nil, parent = nil, attributes = {})
|
10
|
+
if attributes['properties'].class == String
|
11
|
+
attributes['properties'] = attributes['properties'].split(' ')
|
12
|
+
end
|
13
|
+
@attributes = {'id' => itemid, 'href' => itemhref, 'media-type' => itemmediatype}.merge(attributes)
|
14
|
+
@attributes['media-type'] = guess_mediatype if media_type.nil?
|
15
|
+
@parent = parent
|
16
|
+
@parent.register_item(self) unless @parent.nil?
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
['id', 'href', 'media-type', 'fallback', 'properties', 'media-overlay'].each { |name|
|
21
|
+
methodbase = name.sub('-','_')
|
22
|
+
define_method(methodbase + '=') { |val| @attributes[name] = val }
|
23
|
+
define_method('set_' + methodbase) { |val| @attributes[name] = val }
|
24
|
+
define_method(methodbase) { @attributes[name] }
|
25
|
+
}
|
26
|
+
|
27
|
+
def itemid
|
28
|
+
id
|
29
|
+
end
|
30
|
+
|
31
|
+
def mediatype
|
32
|
+
media_type
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](x)
|
36
|
+
@attributes[x]
|
37
|
+
end
|
4
38
|
|
5
|
-
def
|
6
|
-
@
|
7
|
-
|
8
|
-
|
39
|
+
def []=(x,y)
|
40
|
+
@attributes[x] = y
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_property(property)
|
44
|
+
(@attributes['properties'] ||=[]) << property
|
45
|
+
self
|
9
46
|
end
|
10
47
|
|
48
|
+
def cover_image
|
49
|
+
add_property('cover-image')
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_raw_content(data)
|
53
|
+
@content = data
|
54
|
+
end
|
11
55
|
def add_content(io)
|
12
56
|
io.binmode
|
13
57
|
@content = io.read
|
14
58
|
self
|
15
59
|
end
|
16
|
-
|
60
|
+
|
61
|
+
def to_xml(builder, opf_version = '3.0')
|
62
|
+
attr = @attributes.dup
|
63
|
+
if opf_version.to_f < 3.0
|
64
|
+
attr.reject!{ |k,v| k == 'properties' }
|
65
|
+
end
|
66
|
+
if !attr['properties'].nil?
|
67
|
+
attr['properties'] = attr['properties'].join(' ')
|
68
|
+
end
|
69
|
+
builder.item(attr)
|
70
|
+
end
|
71
|
+
|
17
72
|
def guess_mediatype
|
18
|
-
case File.extname(
|
73
|
+
case File.extname(href)
|
19
74
|
when /.(html|xhtml)/i
|
20
75
|
'application/xhtml+xml'
|
21
76
|
when /.css/i
|
@@ -34,6 +89,10 @@ module GEPUB
|
|
34
89
|
'application/oebps-package+xml'
|
35
90
|
when /.ncx/i
|
36
91
|
'application/x-dtbncx+xml'
|
92
|
+
when /.(otf|ttf|ttc)/i
|
93
|
+
'application/vnd.ms-opentype'
|
94
|
+
when /.woff/i
|
95
|
+
'application/font-woff'
|
37
96
|
end
|
38
97
|
end
|
39
98
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
module GEPUB
|
4
|
+
class Manifest
|
5
|
+
include XMLUtil
|
6
|
+
attr_accessor :opf_version
|
7
|
+
def self.parse(manifest_xml, opf_version = '3.0', id_pool = Package::IDPool.new)
|
8
|
+
Manifest.new(opf_version, id_pool) {
|
9
|
+
|manifest|
|
10
|
+
manifest.instance_eval {
|
11
|
+
@xml = manifest_xml
|
12
|
+
@namespaces = @xml.namespaces
|
13
|
+
@attributes = attr_to_hash(@xml.attributes)
|
14
|
+
@items = {}
|
15
|
+
@items_by_href = {}
|
16
|
+
@xml.xpath("//#{ns_prefix(OPF_NS)}:manifest/#{ns_prefix(OPF_NS)}:item", @namespaces).map {
|
17
|
+
|item|
|
18
|
+
i = Item.create(self, attr_to_hash(item.attributes))
|
19
|
+
@items[i.id] = i
|
20
|
+
@items_by_href[i.href] = i
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def id=(val)
|
27
|
+
@attributes['id'] = val
|
28
|
+
end
|
29
|
+
|
30
|
+
def id
|
31
|
+
@attributes['id']
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(opf_version = '3.0', id_pool = Package::IDPool.new)
|
35
|
+
@id_pool = id_pool
|
36
|
+
@attributes = {}
|
37
|
+
@items = {}
|
38
|
+
@items_by_href = {}
|
39
|
+
@opf_version = opf_version
|
40
|
+
yield self if block_given?
|
41
|
+
end
|
42
|
+
|
43
|
+
def item_list
|
44
|
+
@items.dup
|
45
|
+
end
|
46
|
+
|
47
|
+
def item_by_href(href)
|
48
|
+
@items_by_href[href]
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_item(id,href,media_type, attributes = {})
|
52
|
+
@items[id] = item = Item.new(id,href,media_type,self, attributes)
|
53
|
+
@items_by_href[href] = item
|
54
|
+
item
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_xml(builder)
|
58
|
+
builder.manifest(@attributes) {
|
59
|
+
@items.each {
|
60
|
+
|itemid, item|
|
61
|
+
item.to_xml(builder, @opf_version)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def register_item(item)
|
67
|
+
raise "id '#{item.id}' is already in use." if @id_pool[item.id]
|
68
|
+
@id_pool[item.id] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
def unregister_item(item)
|
72
|
+
@items[item.id] = nil
|
73
|
+
@items_by_href[item.href] = nil
|
74
|
+
@id_pool[item.id] = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
data/lib/gepub/meta.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module GEPUB
|
5
|
+
# Holds one metadata with refine meta elements.
|
6
|
+
class Meta
|
7
|
+
attr_accessor :content
|
8
|
+
attr_reader :name
|
9
|
+
def initialize(name, content, parent, attributes= {}, refiners = {})
|
10
|
+
@parent = parent
|
11
|
+
@name = name
|
12
|
+
@content = content
|
13
|
+
@attributes = attributes
|
14
|
+
@refiners = refiners
|
15
|
+
@parent.register_meta(self) unless @parent.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](x)
|
19
|
+
@attributes[x]
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(x,y)
|
23
|
+
@attributes[x] = y
|
24
|
+
end
|
25
|
+
|
26
|
+
def refiner_list(name)
|
27
|
+
return @refiners[name].dup
|
28
|
+
end
|
29
|
+
|
30
|
+
def refiner_clear(name)
|
31
|
+
if !@refiners[name].nil?
|
32
|
+
@refiners[name].each {
|
33
|
+
|refiner|
|
34
|
+
@parent.unregister_meta(refiner)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
@refiners[name]= []
|
38
|
+
end
|
39
|
+
|
40
|
+
def refiner(name)
|
41
|
+
refiner = @refiners[name]
|
42
|
+
if refiner.nil? || refiner.size == 0
|
43
|
+
nil
|
44
|
+
else
|
45
|
+
refiner[0]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# add a refiner.
|
50
|
+
def add_refiner(property, content, attributes = {})
|
51
|
+
(@refiners[property] ||= []) << refiner = Meta.new('meta', content, @parent, { 'property' => property }.merge(attributes)) unless content.nil?
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
# set a 'unique' refiner. all other refiners with same property will be removed.
|
56
|
+
def refine(property, content, attributes = {})
|
57
|
+
if !content.nil?
|
58
|
+
refiner_clear(property)
|
59
|
+
add_refiner(property, content, attributes)
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
['title-type', 'identifier-type', 'display-seq', 'file-as', 'group-position'].each {
|
65
|
+
|name|
|
66
|
+
methodbase = name.sub('-','_')
|
67
|
+
define_method(methodbase + '=') { |val| refine(name, val); }
|
68
|
+
define_method('set_' + methodbase) { |val| refine(name, val); }
|
69
|
+
define_method(methodbase) { refiner(name) }
|
70
|
+
}
|
71
|
+
|
72
|
+
# add alternate script refiner.
|
73
|
+
def add_alternates(alternates = {})
|
74
|
+
alternates.each {
|
75
|
+
|locale, content|
|
76
|
+
add_refiner('alternate-script', content, { 'xml:lang' => locale })
|
77
|
+
}
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_xml(builder, id_pool, ns = nil, additional_attr = {}, opf_version = '3.0')
|
82
|
+
additional_attr ||= {}
|
83
|
+
if @refiners.size > 0 && opf_version.to_f >= 3.0
|
84
|
+
@attributes['id'] = id_pool.generate_key(:prefix => name) if @attributes['id'].nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
# using eval to parametarize Namespace and content.
|
88
|
+
eval "builder#{ ns.nil? || @name == 'meta' ? '' : '[ns]'}.#{@name}(@attributes.reject{|k,v| v.nil?}.merge(additional_attr)#{@content.nil? ? '' : ', @content'})"
|
89
|
+
|
90
|
+
if @refiners.size > 0 && opf_version.to_f >= 3.0
|
91
|
+
additional_attr['refines'] = "##{@attributes['id']}"
|
92
|
+
@refiners.each {
|
93
|
+
|k, ref_list|
|
94
|
+
ref_list.each {
|
95
|
+
|ref|
|
96
|
+
ref.to_xml(builder, id_pool, nil, additional_attr)
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s(locale=nil)
|
103
|
+
localized = nil
|
104
|
+
if !locale.nil?
|
105
|
+
prefix = locale.sub(/^(.+?)-.*/, '\1')
|
106
|
+
regex = Regexp.new("^((" + locale.split('-').join(')?-?(') + ")?)")
|
107
|
+
candidates = @refiners['alternate-script'].select {
|
108
|
+
|refiner|
|
109
|
+
refiner['xml:lang'] =~ /^#{prefix}-?.*/
|
110
|
+
}.sort_by {
|
111
|
+
|x|
|
112
|
+
x['xml:lang'] =~ regex; $1.size
|
113
|
+
}.reverse
|
114
|
+
localized = candidates[0].content if candidates.size > 0
|
115
|
+
end
|
116
|
+
(localized || @content || super).to_s
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module GEPUB
|
6
|
+
# metadata constants
|
7
|
+
module TITLE_TYPE
|
8
|
+
['main','subtitle', 'short', 'collection', 'edition','expanded'].each {
|
9
|
+
|type|
|
10
|
+
const_set(type.upcase, type)
|
11
|
+
}
|
12
|
+
end
|
13
|
+
# Holds data in /package/metadata
|
14
|
+
class Metadata
|
15
|
+
include XMLUtil
|
16
|
+
attr_accessor :opf_version
|
17
|
+
# parse metadata element. metadata_xml should be Nokogiri::XML::Node object.
|
18
|
+
def self.parse(metadata_xml, opf_version = '3.0', id_pool = Package::IDPool.new)
|
19
|
+
Metadata.new(opf_version, id_pool) {
|
20
|
+
|metadata|
|
21
|
+
metadata.instance_eval {
|
22
|
+
@xml = metadata_xml
|
23
|
+
@namespaces = @xml.namespaces
|
24
|
+
CONTENT_NODE_LIST.each {
|
25
|
+
|node|
|
26
|
+
i = 0
|
27
|
+
@content_nodes[node] = parse_node(DC_NS, node).sort_by {
|
28
|
+
|v|
|
29
|
+
[v.refiner('display-seq').to_s.to_i || 2 ** (0.size * 8 - 2) - 1, i += 1]
|
30
|
+
}
|
31
|
+
}
|
32
|
+
@xml.xpath("#{ns_prefix(OPF_NS)}:meta[not(@refines) and @property]", @namespaces).each {
|
33
|
+
|node|
|
34
|
+
@meta[node['property']] = create_meta(node)
|
35
|
+
}
|
36
|
+
|
37
|
+
@oldstyle_meta = parse_opf2_meta
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(opf_version = '3.0',id_pool = Package::IDPool.new)
|
43
|
+
@id_pool = id_pool
|
44
|
+
@metalist = {}
|
45
|
+
@content_nodes = {}
|
46
|
+
@meta = {}
|
47
|
+
@oldstyle_meta = []
|
48
|
+
@opf_version = opf_version
|
49
|
+
@namespaces = { 'xmlns:dc' => DC_NS }
|
50
|
+
@namespaces['xmlns:opf'] = OPF_NS if @opf_version.to_f < 3.0
|
51
|
+
yield self if block_given?
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_xml(builder)
|
55
|
+
builder.metadata(@namespaces) {
|
56
|
+
@content_nodes.each {
|
57
|
+
|name, list|
|
58
|
+
list.each {
|
59
|
+
|meta|
|
60
|
+
meta.to_xml(builder, @id_pool, ns_prefix(DC_NS), nil, @opf_version)
|
61
|
+
}
|
62
|
+
}
|
63
|
+
@oldstyle_meta.each {
|
64
|
+
|node|
|
65
|
+
node.to_xml(builder, @id_pool, nil)
|
66
|
+
}
|
67
|
+
}
|
68
|
+
@xml
|
69
|
+
end
|
70
|
+
|
71
|
+
def main_title # should make it obsolete?
|
72
|
+
@content_nodes['title'][0].content
|
73
|
+
end
|
74
|
+
|
75
|
+
def oldstyle_meta
|
76
|
+
@oldstyle_meta.dup
|
77
|
+
end
|
78
|
+
|
79
|
+
def oldstyle_meta_clear
|
80
|
+
@oldstyle_meta.each {
|
81
|
+
|meta|
|
82
|
+
unregister_meta(meta)
|
83
|
+
}
|
84
|
+
@oldstyle_meta = []
|
85
|
+
end
|
86
|
+
|
87
|
+
CONTENT_NODE_LIST = ['identifier','title', 'language', 'contributor', 'creator', 'coverage', 'date','description','format ','publisher','relation','rights','source','subject','type'].each {
|
88
|
+
|node|
|
89
|
+
define_method(node + '_list') { @content_nodes[node].dup }
|
90
|
+
define_method(node + '_clear') {
|
91
|
+
if !@content_nodes[node].nil?
|
92
|
+
@content_nodes[node].each { |x| unregister_meta(x) };
|
93
|
+
@content_nodes[node] = []
|
94
|
+
end
|
95
|
+
}
|
96
|
+
|
97
|
+
#TODO: should override for 'title'. // for 'main title' not always comes first.
|
98
|
+
define_method(node) {
|
99
|
+
if !@content_nodes[node].nil? && @content_nodes[node].size > 0
|
100
|
+
@content_nodes[node][0]
|
101
|
+
end
|
102
|
+
}
|
103
|
+
|
104
|
+
define_method('add_' + node) {
|
105
|
+
|content, id|
|
106
|
+
add_metadata(node, content, id)
|
107
|
+
}
|
108
|
+
|
109
|
+
define_method('set_' + node) {
|
110
|
+
|content, id|
|
111
|
+
send(node + "_clear")
|
112
|
+
add_metadata(node, content, id)
|
113
|
+
}
|
114
|
+
|
115
|
+
define_method(node+'=') {
|
116
|
+
|content|
|
117
|
+
send(node + "_clear")
|
118
|
+
add_metadata(node, content)
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
def add_identifier(string, id, type=nil)
|
123
|
+
raise 'id #{id} is already in use' if @id_pool[id]
|
124
|
+
identifier = add_metadata('identifier', string, id)
|
125
|
+
identifier.refine('identifier-type', type) unless type.nil?
|
126
|
+
identifier
|
127
|
+
end
|
128
|
+
|
129
|
+
def identifier_by_id(id)
|
130
|
+
@content_nodes['identifier'].each {
|
131
|
+
|x|
|
132
|
+
return x.content if x['id'] == id
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def add_metadata(name, content, id = nil)
|
137
|
+
meta = Meta.new(name, content, self, { 'id' => id })
|
138
|
+
(@content_nodes[name] ||= []) << meta
|
139
|
+
yield self if block_given?
|
140
|
+
meta
|
141
|
+
end
|
142
|
+
|
143
|
+
def add_title(content, id = nil, title_type = nil)
|
144
|
+
meta = add_metadata('title', content, id).refine('title-type', title_type)
|
145
|
+
yield meta if block_given?
|
146
|
+
meta
|
147
|
+
end
|
148
|
+
|
149
|
+
def add_person(name, content, id = nil, role = 'aut')
|
150
|
+
meta = add_metadata(name, content, id).refine('role', role)
|
151
|
+
yield meta if block_given?
|
152
|
+
meta
|
153
|
+
end
|
154
|
+
|
155
|
+
def add_creator(content, id = nil, role = 'aut')
|
156
|
+
meta = add_person('creator', content, id, role)
|
157
|
+
yield meta if block_given?
|
158
|
+
meta
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_contributor(content, id=nil, role=nil)
|
162
|
+
meta = add_person('contributor', content, id, role)
|
163
|
+
yield meta if block_given?
|
164
|
+
meta
|
165
|
+
end
|
166
|
+
|
167
|
+
def set_lastmodified(date=nil)
|
168
|
+
date ||= Time.now
|
169
|
+
(@content_nodes['meta'] ||= []).each {
|
170
|
+
|meta|
|
171
|
+
if (meta['property'] == 'dcterms:modified')
|
172
|
+
@content_nodes['meta'].delete meta
|
173
|
+
end
|
174
|
+
}
|
175
|
+
add_metadata('meta', date.utc.strftime('%Y-%m-%dT%H:%M:%SZ'))['property'] = 'dcterms:modified'
|
176
|
+
end
|
177
|
+
|
178
|
+
def add_oldstyle_meta(content, attributes = {})
|
179
|
+
meta = Meta.new('meta', content, self, attributes)
|
180
|
+
(@oldstyle_meta ||= []) << meta
|
181
|
+
meta
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
def register_meta(meta)
|
186
|
+
if !meta['id'].nil?
|
187
|
+
raise "id '#{meta['id']}' is already in use." if @id_pool[meta['id']]
|
188
|
+
@metalist[meta['id']] = meta
|
189
|
+
@id_pool[meta['id']] = true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def unregister_meta(meta)
|
194
|
+
if meta['id'].nil?
|
195
|
+
@metalist[meta['id']] = nil
|
196
|
+
@id_pool[meta['id']] = nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
private
|
201
|
+
def parse_node(ns, node)
|
202
|
+
@xml.xpath("#{ns_prefix(ns)}:#{node}", @namespaces).map {
|
203
|
+
|node|
|
204
|
+
create_meta(node)
|
205
|
+
}
|
206
|
+
end
|
207
|
+
|
208
|
+
def create_meta(node)
|
209
|
+
Meta.new(node.name, node.content, self, attr_to_hash(node.attributes), collect_refiners(node['id']))
|
210
|
+
end
|
211
|
+
|
212
|
+
def collect_refiners(id)
|
213
|
+
r = {}
|
214
|
+
if !id.nil?
|
215
|
+
@xml.xpath("//#{ns_prefix(OPF_NS)}:meta[@refines='##{id}']", @namespaces).each {
|
216
|
+
|node|
|
217
|
+
(r[node['property']] ||= []) << create_meta(node)
|
218
|
+
}
|
219
|
+
end
|
220
|
+
r
|
221
|
+
end
|
222
|
+
|
223
|
+
def parse_opf2_meta
|
224
|
+
@xml.xpath("#{ns_prefix(OPF_NS)}:meta[not(@refines) and not(@property)]").map {
|
225
|
+
|node|
|
226
|
+
create_meta(node)
|
227
|
+
}
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|