rbook-onix 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/LICENSE +13 -0
- data/README +0 -0
- data/Rakefile +90 -0
- data/examples/stream_reader.rb +13 -0
- data/lib/rbook/onix.rb +70 -0
- data/lib/rbook/onix/contributor.rb +59 -0
- data/lib/rbook/onix/lists.rb +2 -0
- data/lib/rbook/onix/lists/contributor_role.rb +10 -0
- data/lib/rbook/onix/lists/product_form.rb +100 -0
- data/lib/rbook/onix/message.rb +121 -0
- data/lib/rbook/onix/product.rb +208 -0
- data/lib/rbook/onix/sales_restriction.rb +50 -0
- data/lib/rbook/onix/stream_reader.rb +120 -0
- data/lib/rbook/onix/stream_writer.rb +40 -0
- data/lib/rbook/onix/supply_detail.rb +75 -0
- data/lib/rbook/onix/xchar.rb +62 -0
- data/specs/contributor_class_spec.rb +33 -0
- data/specs/contributor_with_data_spec.rb +36 -0
- data/specs/data/10_products.xml +469 -0
- data/specs/data/2_products_utf16.xml +0 -0
- data/specs/data/abingdon.xml +38931 -0
- data/specs/data/augsburg.xml +39009 -0
- data/specs/data/chalice.xml +10851 -0
- data/specs/data/eerdsman.xml +36942 -0
- data/specs/data/invalid_no_product.xml +9 -0
- data/specs/data/invalid_xml.xml +24 -0
- data/specs/data/not_xml.csv +1 -0
- data/specs/data/single_product.xml +55 -0
- data/specs/data/xml_not_onix.xml +7 -0
- data/specs/message_class_spec.rb +110 -0
- data/specs/message_with_data_spec.rb +81 -0
- data/specs/product_class_spec.rb +42 -0
- data/specs/product_with_data_spec.rb +66 -0
- data/specs/sales_restriction_class_spec.rb +32 -0
- data/specs/sales_restriction_with_data_spec.rb +31 -0
- data/specs/stream_reader_spec.rb +31 -0
- data/specs/stream_writer_spec.rb +30 -0
- data/specs/supply_detail_class_spec.rb +35 -0
- data/specs/supply_detail_with_data_spec.rb +42 -0
- data/specs/xchar_spec.rb +39 -0
- metadata +116 -0
data/lib/rbook/onix.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + "/../")
|
2
|
+
|
3
|
+
require 'rbook/onix/contributor'
|
4
|
+
require 'rbook/onix/lists'
|
5
|
+
require 'rbook/onix/message'
|
6
|
+
require 'rbook/onix/product'
|
7
|
+
require 'rbook/onix/sales_restriction'
|
8
|
+
require 'rbook/onix/supply_detail'
|
9
|
+
require 'rbook/onix/xchar'
|
10
|
+
require 'rbook/onix/stream_reader'
|
11
|
+
require 'rbook/onix/stream_writer'
|
12
|
+
require 'rbook/isbn'
|
13
|
+
|
14
|
+
module RBook
|
15
|
+
|
16
|
+
# Ruby classes for working with ONIX files. Currently only supports a very limited
|
17
|
+
# subset of the ONIX specification, but the core attributes are there. More will be
|
18
|
+
# added over time.
|
19
|
+
#
|
20
|
+
# = Usage
|
21
|
+
#
|
22
|
+
# == Loading from an REXML document
|
23
|
+
#
|
24
|
+
# require 'rubygems'
|
25
|
+
# require 'rbook/onix'
|
26
|
+
# file = File.open("./onix_message.xml", "r")
|
27
|
+
# doc = REXML::Document.new(file)
|
28
|
+
# msg = Onix::Message.load_from_xmldoc(doc)
|
29
|
+
#
|
30
|
+
# puts msg.from_company
|
31
|
+
#
|
32
|
+
# == Creation
|
33
|
+
#
|
34
|
+
# require 'rubygems'
|
35
|
+
# require 'rbook/onix'
|
36
|
+
# msg = RBook::Onix::Message.new
|
37
|
+
# msg.from_company = 'XYZ Books'
|
38
|
+
# msg.from_name = 'Joe Blogs'
|
39
|
+
# msg.message_note = "A sample ONIX file"
|
40
|
+
#
|
41
|
+
# product = RBook::Onix::Product.new
|
42
|
+
# product.product_identifier = "020161622X"
|
43
|
+
# product.title = "Pragmatic Programmer"
|
44
|
+
# product.subtitle = "From Journeyman to Master"
|
45
|
+
# product.form = "BB"
|
46
|
+
# product.description = "A book about programming and stuff"
|
47
|
+
#
|
48
|
+
# contributor1 = RBook::Onix::Contributor.new
|
49
|
+
# contributor1.name_inverted = "Hunt, Andrew"
|
50
|
+
# contributor1.role = "A01"
|
51
|
+
# contributor1.sequence = "01"
|
52
|
+
# contributor2 = RBook::Onix::Contributor.new
|
53
|
+
# contributor2.name_inverted = "Thomas, David"
|
54
|
+
# contributor2.role = "A01"
|
55
|
+
# contributor2.sequence = "02"
|
56
|
+
# product.add_contributor(contributor1)
|
57
|
+
# product.add_contributor(contributor2)
|
58
|
+
#
|
59
|
+
# supply_detail = RBook::Onix::SupplyDetail.new
|
60
|
+
# supply_detail.supplier_name = "Rainbow Book Agencies"
|
61
|
+
# supply_detail.price = BigDecimal.new(29.95)
|
62
|
+
# supply_detail.availability = "CS"
|
63
|
+
# product.add_supply_detail(supply_detail)
|
64
|
+
#
|
65
|
+
# msg.add_product(product)
|
66
|
+
# puts msg.to_s
|
67
|
+
module Onix
|
68
|
+
class InvalidRubyVersionError < RuntimeError;end;
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module RBook
|
4
|
+
module Onix
|
5
|
+
|
6
|
+
class Contributor
|
7
|
+
attr_accessor :sequence_number, :role, :name, :name_inverted
|
8
|
+
|
9
|
+
# Attempts to create a contributor object using the supplied xml element
|
10
|
+
def Contributor.load_from_element(element)
|
11
|
+
raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
|
12
|
+
|
13
|
+
if REXML::XPath.first(element, '//Contributor').nil?
|
14
|
+
raise LoadError, 'supplied REXML document object does not appear contain a valid contributor fragment'
|
15
|
+
end
|
16
|
+
|
17
|
+
contributor = Contributor.new
|
18
|
+
|
19
|
+
tmp = REXML::XPath.first(element, '//Contributor/SequenceNumber')
|
20
|
+
contributor.sequence_number = tmp.text if tmp != nil
|
21
|
+
|
22
|
+
tmp = REXML::XPath.first(element, '//Contributor/ContributorRole')
|
23
|
+
contributor.role = tmp.text if tmp != nil
|
24
|
+
|
25
|
+
tmp = REXML::XPath.first(element, '//Contributor/PersonName')
|
26
|
+
contributor.name = tmp.text if tmp != nil
|
27
|
+
|
28
|
+
tmp = REXML::XPath.first(element, '//Contributor/PersonNameInverted')
|
29
|
+
contributor.name_inverted = tmp.text if tmp != nil
|
30
|
+
|
31
|
+
return contributor
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return an xml element representing this contributor
|
36
|
+
def to_element
|
37
|
+
raise 'Contributor must have a sequence number to create an element' if @sequence_number.nil?
|
38
|
+
raise 'Contributor must have a role to create an element' if @role.nil?
|
39
|
+
raise '' if @name_inverted.nil? && @name.nil?
|
40
|
+
|
41
|
+
contributor = REXML::Element.new('Contributor')
|
42
|
+
contributor.add_element('SequenceNumber').text = self.sequence_number
|
43
|
+
contributor.add_element('ContributorRole').text = self.role.to_xs
|
44
|
+
contributor.add_element('PersonName').text = name.to_xs unless self.name.nil?
|
45
|
+
contributor.add_element('PersonNameInverted').text = self.name_inverted.to_xs unless self.name_inverted.nil?
|
46
|
+
|
47
|
+
return contributor
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return an XML string representing this contributor
|
51
|
+
def to_s
|
52
|
+
tmp = to_element
|
53
|
+
output = ''
|
54
|
+
tmp.write(output, 0)
|
55
|
+
return output
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module RBook
|
2
|
+
module Onix
|
3
|
+
module Lists
|
4
|
+
|
5
|
+
FORM_CODES = [
|
6
|
+
['Undefined', '00'],
|
7
|
+
['Audio', 'AA'],
|
8
|
+
['Audio - Cassette', 'AB'],
|
9
|
+
['Audio - CD', 'AC'],
|
10
|
+
['Audio - DAT', 'AD'],
|
11
|
+
['Audio - Disk', 'AE'],
|
12
|
+
['Audio - Tape', 'AF'],
|
13
|
+
['Audio - Other', 'AZ'],
|
14
|
+
['Book', 'BA'],
|
15
|
+
['Book - Hardback', 'BB'],
|
16
|
+
['Book - Paperback', 'BC'],
|
17
|
+
['Book - Loose-leaf', 'BD'],
|
18
|
+
['Book - Spiral Bound', 'BE'],
|
19
|
+
['Book - Pamphlet', 'BF'],
|
20
|
+
['Book - Leather / Fine Binding', 'BG'],
|
21
|
+
['Book - Board', 'BH'],
|
22
|
+
['Book - Rag', 'BI'],
|
23
|
+
['Book - Bath', 'BJ'],
|
24
|
+
['Book - Other', 'BZ'],
|
25
|
+
['Cartographic - Sheet Map', 'CA'],
|
26
|
+
['Cartographic - Sheet Map, Folded', 'CB'],
|
27
|
+
['Cartographic - Sheet Map, Flat', 'CC'],
|
28
|
+
['Cartographic - Sheet Map, Rolled', 'CD'],
|
29
|
+
['Cartographic - Globe', 'CE'],
|
30
|
+
['Cartographic - Other', 'CZ'],
|
31
|
+
['Digital', 'DA'],
|
32
|
+
['Digital - CDROM', 'DB'],
|
33
|
+
['Digital - CD-Interactive', 'DC'],
|
34
|
+
['Digital - DVD', 'DD'],
|
35
|
+
['Digital - Game Cartridge', 'DE'],
|
36
|
+
['Digital - Diskette', 'DF'],
|
37
|
+
['Digital - Electronic Book Text', 'DG'],
|
38
|
+
['Digital - Online File', 'DH'],
|
39
|
+
['Digital - Other', 'DZ'],
|
40
|
+
['Film or Transparency', 'FA'],
|
41
|
+
['Film', 'FB'],
|
42
|
+
['Film - Slides', 'FC'],
|
43
|
+
['Film - OHP Transparencies', 'FD'],
|
44
|
+
['Film - Other ', 'FZ'],
|
45
|
+
['Microform', 'MA'],
|
46
|
+
['Microform - Microfiche', 'MB'],
|
47
|
+
['Microform - Microfilm', 'MC'],
|
48
|
+
['Microform - Other', 'MZ'],
|
49
|
+
['Print - Misc', 'PA'],
|
50
|
+
['Print - Address Book', 'PB'],
|
51
|
+
['Print - Calendar', 'PC'],
|
52
|
+
['Print - Cards', 'PD'],
|
53
|
+
['Print - Copymasters', 'PE'],
|
54
|
+
['Print - Diary', 'PF'],
|
55
|
+
['Print - Frieze', 'PG'],
|
56
|
+
['Print - Kit', 'PH'],
|
57
|
+
['Print - Sheet Music', 'PI'],
|
58
|
+
['Print - Postcard Book or Pack', 'PJ'],
|
59
|
+
['Print - Poster', 'PK'],
|
60
|
+
['Print - Record Book', 'PL'],
|
61
|
+
['Print - Wallet', 'PM'],
|
62
|
+
['Print - Pictures or Photographs', 'PN'],
|
63
|
+
['Print - Wallchart', 'PO'],
|
64
|
+
['Print - Other', 'PZ'],
|
65
|
+
['Video', 'VA'],
|
66
|
+
['Video - VHS, PAL', 'VB'],
|
67
|
+
['Video - VHA, NTSC', 'VC'],
|
68
|
+
['Video - Betamax, PAL', 'VD'],
|
69
|
+
['Video - Betamax, NTSC', 'VE'],
|
70
|
+
['Video - disk', 'VF'],
|
71
|
+
['Video - VHS, SECAM', 'VG'],
|
72
|
+
['Video - Betamax, SECAM', 'VH'],
|
73
|
+
['Video - Other Format','VZ'],
|
74
|
+
['Multiple - Mixed Media Product', 'WW'],
|
75
|
+
['Misc - Quantity Pack', 'WX'],
|
76
|
+
['Misc - Trade-only Material', 'XA'],
|
77
|
+
['Misc - Dumpbim - Empty', 'XB'],
|
78
|
+
['Misc - Dumpbin - Filled', 'XC'],
|
79
|
+
['Misc - Counterpack - Empty', 'XD'],
|
80
|
+
['Misc - Counterpack - Filled', 'XE'],
|
81
|
+
['Misc - Poster', 'XF'],
|
82
|
+
['Misc - Shelf Strip', 'XG'],
|
83
|
+
['Misc - Window Piece', 'XH'],
|
84
|
+
['Misc - Streamer', 'XI'],
|
85
|
+
['Misc - Spinner', 'XJ'],
|
86
|
+
['Misc - Large Book Display', 'XK'],
|
87
|
+
['Misc - Shrink Wrapped Pack', 'XL'],
|
88
|
+
['Misc - Other Point of Sale', 'XZ'],
|
89
|
+
['General Merchandise', 'ZA'],
|
90
|
+
['Misc - Doll', 'ZB'],
|
91
|
+
['Misc - Soft Toy', 'ZC'],
|
92
|
+
['Misc - Toy', 'ZD'],
|
93
|
+
['Misc - Game', 'ZE'],
|
94
|
+
['Misc - T-shirt', 'ZF'],
|
95
|
+
['Misc - Other Merchandise', 'ZZ'],
|
96
|
+
].freeze
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module RBook
|
4
|
+
module Onix
|
5
|
+
|
6
|
+
class Message
|
7
|
+
attr_reader :products
|
8
|
+
attr_accessor :from_company, :from_person, :from_email, :message_note, :sent_date, :to_person, :to_company
|
9
|
+
|
10
|
+
VERSION = 0.1
|
11
|
+
ONIX_DTD_URL = "http://www.editeur.org/onix/2.1/reference/onix-international.dtd"
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@products = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.check_ruby_version
|
18
|
+
raise InvalidRubyVersionError, 'Ruby 1.8.6 or higher is required to use this class' unless RUBY_VERSION >= "1.8.6"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Attempts to create a message object using thge supplied xml string
|
22
|
+
def self.load_from_string(str)
|
23
|
+
self.check_ruby_version
|
24
|
+
begin
|
25
|
+
doc = REXML::Document.new(str)
|
26
|
+
self.load_from_xmldoc(doc)
|
27
|
+
rescue REXML::ParseException => e
|
28
|
+
raise LoadError, e.message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Attempts to create a message object using thge supplied xml document
|
33
|
+
def self.load_from_xmldoc(doc)
|
34
|
+
self.check_ruby_version
|
35
|
+
raise ArgumentError, 'load_from_xmldoc expects a REXML document object' unless doc.class == REXML::Document
|
36
|
+
if REXML::XPath.first(doc, '/ONIXMessage/').nil? ||
|
37
|
+
REXML::XPath.first(doc, '/ONIXMessage/Header').nil? ||
|
38
|
+
REXML::XPath.first(doc, '/ONIXMessage/Product').nil?
|
39
|
+
raise LoadError, 'supplied REXML document object does not appear to be a valid ONIX file'
|
40
|
+
end
|
41
|
+
|
42
|
+
msg = Onix::Message.new
|
43
|
+
|
44
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/FromCompany')
|
45
|
+
msg.from_company = tmpelement.text if tmpelement != nil
|
46
|
+
|
47
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/FromPerson')
|
48
|
+
msg.from_person = tmpelement.text if tmpelement != nil
|
49
|
+
|
50
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/FromEmail')
|
51
|
+
msg.from_email = tmpelement.text if tmpelement != nil
|
52
|
+
|
53
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/SentDate')
|
54
|
+
tmpdate = Date.civil(tmpelement.text[0,4].to_i, tmpelement.text[4,2].to_i, tmpelement.text[6,2].to_i) if tmpelement != nil
|
55
|
+
msg.sent_date = tmpdate if tmpdate != nil
|
56
|
+
|
57
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/ToCompany')
|
58
|
+
msg.to_company = tmpelement.text if tmpelement != nil
|
59
|
+
|
60
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/ToPerson')
|
61
|
+
msg.to_person = tmpelement.text if tmpelement != nil
|
62
|
+
|
63
|
+
products = REXML::XPath.each(doc, '/ONIXMessage/Product') { |product|
|
64
|
+
msg.add_product(Onix::Product.load_from_element(product))
|
65
|
+
}
|
66
|
+
|
67
|
+
return msg
|
68
|
+
end
|
69
|
+
|
70
|
+
# Adds a new product to this message
|
71
|
+
def add_product(product)
|
72
|
+
raise ArgumentError, 'Argument must be a Onix::Product' if product.class != Onix::Product
|
73
|
+
@products << product
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns an XML string representing this message
|
77
|
+
def to_s
|
78
|
+
doc = to_xml
|
79
|
+
output = ''
|
80
|
+
doc.write(output, 0)
|
81
|
+
return output
|
82
|
+
end
|
83
|
+
|
84
|
+
def header
|
85
|
+
raise 'from_compnay must be set to create an onix message' if from_company == nil
|
86
|
+
raise 'from_person must be set to create an onix message' if from_person == nil
|
87
|
+
|
88
|
+
header = REXML::Element.new('Header')
|
89
|
+
header.add_element('FromCompany').text = from_company.to_xs
|
90
|
+
header.add_element('FromPerson').text = from_person.to_xs
|
91
|
+
header.add_element('FromEmail').text = from_email.to_xs unless from_email.nil?
|
92
|
+
header.add_element('MessageNote').text = message_note.to_xs unless message_note.nil?
|
93
|
+
header.add_element('ToCompany').text = to_company.to_xs unless to_company.nil?
|
94
|
+
header.add_element('ToPerson').text = to_person.to_xs unless to_person.nil?
|
95
|
+
|
96
|
+
now = Time.now
|
97
|
+
header.add_element('SentDate').text = "%.4d%.2d%.2d" % [ now.year, now.month, now.day ]
|
98
|
+
return header
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns an XML document representing this message
|
102
|
+
def to_xml
|
103
|
+
raise 'There must be at least 1 product to burn' if @products.size < 1
|
104
|
+
|
105
|
+
doc = REXML::Document.new
|
106
|
+
doc << REXML::XMLDecl.new
|
107
|
+
doc << REXML::DocType.new('ONIXMessage', "SYSTEM \"#{ONIX_DTD_URL}\"")
|
108
|
+
msg = doc.add_element('ONIXMessage')
|
109
|
+
msg.add_element(header)
|
110
|
+
|
111
|
+
@products.each do |product|
|
112
|
+
prod = msg.add_element(product.to_element)
|
113
|
+
end
|
114
|
+
|
115
|
+
return doc
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module RBook
|
4
|
+
module Onix
|
5
|
+
class Product
|
6
|
+
|
7
|
+
attr_accessor :record_reference, :notification_type, :product_identifier
|
8
|
+
attr_accessor :title, :subtitle, :pages, :publication_date, :price
|
9
|
+
attr_accessor :description, :form, :bicmainsubject, :publisher, :supplier
|
10
|
+
attr_accessor :website, :edition, :cover_image
|
11
|
+
attr_reader :contributors, :sales_restrictions, :supply_details
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@contributors = []
|
15
|
+
@supply_details = []
|
16
|
+
@sales_restrictions = []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Attempts to create a product object using the supplied xml element
|
20
|
+
def Product.load_from_element(element)
|
21
|
+
raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
|
22
|
+
|
23
|
+
if REXML::XPath.first(element, '//Product').nil?
|
24
|
+
raise LoadError, 'supplied REXML document object does not appear contain a valid product fragment'
|
25
|
+
end
|
26
|
+
|
27
|
+
product = Product.new
|
28
|
+
|
29
|
+
tmp = REXML::XPath.first(element, '//Product/RecordReference')
|
30
|
+
product.record_reference = tmp.text if tmp != nil
|
31
|
+
|
32
|
+
tmp = REXML::XPath.first(element, '//Product/NotificationType')
|
33
|
+
product.notification_type = tmp.text if tmp != nil
|
34
|
+
|
35
|
+
tmp = REXML::XPath.first(element, '//Product/ProductIdentifier/IDValue')
|
36
|
+
product.product_identifier = tmp.text if tmp != nil
|
37
|
+
|
38
|
+
tmp = REXML::XPath.first(element, '//Product/ProductForm')
|
39
|
+
product.form = tmp.text if tmp != nil
|
40
|
+
|
41
|
+
tmp = REXML::XPath.first(element, '//Product/NumberOfPages')
|
42
|
+
product.pages = tmp.text if tmp != nil
|
43
|
+
|
44
|
+
tmp = REXML::XPath.first(element, '//Product/BICMainSubject')
|
45
|
+
product.bicmainsubject = tmp.text if tmp != nil
|
46
|
+
|
47
|
+
REXML::XPath.each(element, '//Product/MediaFile') { |mediafile|
|
48
|
+
type = REXML::XPath.first(element, '//Product/MediaFile/MediaFileTypeCode')
|
49
|
+
# cover image
|
50
|
+
if type.text.eql?("04")
|
51
|
+
url = REXML::XPath.first(element, '//Product/MediaFile/MediaFileLink')
|
52
|
+
product.cover_image = url.text unless url.nil?
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
tmp = REXML::XPath.first(element, '//Product/DistinctiveTitle')
|
57
|
+
if !tmp.nil?
|
58
|
+
product.title = tmp.text
|
59
|
+
tmp = REXML::XPath.first(element, '//Product/Subtitle') if !tmp.nil?
|
60
|
+
product.subtitle = tmp.text
|
61
|
+
else
|
62
|
+
tmp = REXML::XPath.first(element, '//Product/Title/TitleText')
|
63
|
+
product.title = tmp.text unless tmp.nil?
|
64
|
+
tmp = REXML::XPath.first(element, '//Product/Title/Subtitle')
|
65
|
+
product.subtitle = tmp.text unless tmp.nil?
|
66
|
+
end
|
67
|
+
|
68
|
+
tmp = REXML::XPath.first(element, '//Product/EditionNumber')
|
69
|
+
product.edition = tmp.text if tmp != nil
|
70
|
+
|
71
|
+
tmp = REXML::XPath.first(element, '//Product/PublicationDate')
|
72
|
+
tmpdate = Date.civil(tmp.text[0,4].to_i, tmp.text[4,2].to_i, tmp.text[6,2].to_i) if tmp != nil
|
73
|
+
product.publication_date = tmpdate if tmpdate != nil
|
74
|
+
|
75
|
+
tmp = REXML::XPath.first(element, '//Product/Publisher/PublisherName')
|
76
|
+
product.publisher = tmp.text if tmp != nil
|
77
|
+
|
78
|
+
REXML::XPath.each(element, '//Product/Contributor') { |contributor|
|
79
|
+
product.add_contributor(Onix::Contributor.load_from_element(contributor))
|
80
|
+
}
|
81
|
+
|
82
|
+
REXML::XPath.each(element, '//Product/SupplyDetail') { |detail|
|
83
|
+
product.add_supply_detail(Onix::SupplyDetail.load_from_element(detail))
|
84
|
+
}
|
85
|
+
|
86
|
+
return product
|
87
|
+
end
|
88
|
+
|
89
|
+
# Add a new contributor to this product
|
90
|
+
def add_contributor(newAuthor)
|
91
|
+
raise ArgumentError, 'Argument to add_contributor must be an ONIX::Contributor' if newAuthor.class != Contributor
|
92
|
+
@contributors << newAuthor
|
93
|
+
end
|
94
|
+
|
95
|
+
# Add a new contributor to this product
|
96
|
+
def add_sales_restriction(restriction)
|
97
|
+
raise ArgumentError, 'Argument to add_sales_restriction must be an ONIX::SalesRestriction' if restriction.class != SalesRestriction
|
98
|
+
@sales_restrictions << restriction
|
99
|
+
end
|
100
|
+
|
101
|
+
# Add a new contributor to this product
|
102
|
+
def add_supply_detail(detail)
|
103
|
+
raise ArgumentError, 'Argument to add_supply_detail must be an ONIX::SupplyDetail' if detail.class != SupplyDetail
|
104
|
+
@supply_details << detail
|
105
|
+
end
|
106
|
+
|
107
|
+
# Return an xml element representing this contributor
|
108
|
+
def to_element
|
109
|
+
raise 'product_identifier must be set' if self.product_identifier.nil?
|
110
|
+
|
111
|
+
product = REXML::Element.new('Product')
|
112
|
+
|
113
|
+
if self.record_reference
|
114
|
+
product.add_element('RecordReference').text = self.record_reference
|
115
|
+
else
|
116
|
+
product.add_element('RecordReference').text = self.product_identifier
|
117
|
+
end
|
118
|
+
|
119
|
+
product.add_element('NotificationType').text = '03'
|
120
|
+
|
121
|
+
product_identifier = REXML::Element.new('ProductIdentifier')
|
122
|
+
if ISBN::valid_isbn13?(self.product_identifier)
|
123
|
+
product_identifier.add_element('ProductIDType').text = '03'
|
124
|
+
elsif ISBN::valid_isbn10?(self.product_identifier)
|
125
|
+
product_identifier.add_element('ProductIDType').text = '02'
|
126
|
+
else
|
127
|
+
product_identifier.add_element('ProductIDType').text = '01'
|
128
|
+
end
|
129
|
+
product_identifier.add_element('IDValue').text = self.product_identifier.to_xs
|
130
|
+
product.add_element(product_identifier)
|
131
|
+
|
132
|
+
if form != nil
|
133
|
+
product.add_element('ProductForm').text = self.form.to_xs
|
134
|
+
end
|
135
|
+
|
136
|
+
product.add_element('NoSeries')
|
137
|
+
|
138
|
+
title = REXML::Element.new('Title')
|
139
|
+
title.add_element('TitleType').text = '01'
|
140
|
+
title.add_element('TitleText').text = self.title.to_xs unless self.title.nil?
|
141
|
+
title.add_element('Subtitle').text = self.subtitle.to_xs unless self.subtitle.nil?
|
142
|
+
product.add_element(title)
|
143
|
+
|
144
|
+
if website != nil
|
145
|
+
product_website = REXML::Element.new('Website')
|
146
|
+
product_website.add_element('WebsiteLink').text = self.website.to_xs
|
147
|
+
product.add_element(product_website)
|
148
|
+
end
|
149
|
+
|
150
|
+
unless cover_image.nil?
|
151
|
+
product_mf = REXML::Element.new('MediaFile')
|
152
|
+
product_mf.add_element('MediaFileTypeCode').text = "04"
|
153
|
+
product_mf.add_element('MediaFileLinkTypeCode').text = "01"
|
154
|
+
product_mf.add_element('MediaFileLink').text = self.cover_image.to_xs
|
155
|
+
product.add_element(product_mf)
|
156
|
+
end
|
157
|
+
|
158
|
+
contributors.each do |contributor|
|
159
|
+
product.add_element(contributor.to_element)
|
160
|
+
end
|
161
|
+
|
162
|
+
product.add_element('NoEdition')
|
163
|
+
|
164
|
+
product.add_element('NumberOfPages').text = self.pages.to_s unless self.pages.nil?
|
165
|
+
|
166
|
+
if bicmainsubject != nil
|
167
|
+
product.add_element('BICMainSubject').text = self.bicmainsubject.to_xs
|
168
|
+
end
|
169
|
+
|
170
|
+
if description != nil
|
171
|
+
other_text = REXML::Element.new('OtherText')
|
172
|
+
other_text.add_element('TextTypeCode').text = '01'
|
173
|
+
other_text.add_element('Text').text = self.description.to_xs
|
174
|
+
product.add_element(other_text)
|
175
|
+
end
|
176
|
+
|
177
|
+
if publisher != nil
|
178
|
+
publisher = REXML::Element.new('Publisher')
|
179
|
+
publisher.add_element('PublishingRole').text = '01'
|
180
|
+
publisher.add_element('PublisherName').text = self.publisher.to_xs
|
181
|
+
product.add_element(publisher)
|
182
|
+
end
|
183
|
+
|
184
|
+
supply_details.each do |detail|
|
185
|
+
product.add_element(detail.to_element)
|
186
|
+
end
|
187
|
+
|
188
|
+
sales_restrictions.each do |restriction|
|
189
|
+
product.add_element(restriction.to_element)
|
190
|
+
end
|
191
|
+
|
192
|
+
if publication_date != nil
|
193
|
+
product.add_element('PublicationDate').text = "%.4d%.2d%.2d" % [ publication_date.year, publication_date.month, publication_date.day ]
|
194
|
+
end
|
195
|
+
|
196
|
+
return product
|
197
|
+
end
|
198
|
+
|
199
|
+
# return an XML string representing this contributor
|
200
|
+
def to_s
|
201
|
+
output = ''
|
202
|
+
to_element.write(output, 0)
|
203
|
+
return output
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|