rbook 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/COPYING +340 -0
- data/LICENSE +13 -0
- data/README +16 -0
- data/Rakefile +206 -0
- data/examples/titlepage.rb +14 -0
- data/examples/www/find_all.rb +23 -0
- data/examples/www/find_cover_from_amazon.rb +12 -0
- data/examples/www/find_url_from_rainbow.rb +12 -0
- data/examples/www/list.rb +13 -0
- data/lib/rbook/bisac.rb +175 -0
- data/lib/rbook/errors.rb +7 -0
- data/lib/rbook/isbn.rb +249 -0
- data/lib/rbook/onix.rb +68 -0
- data/lib/rbook/onix/contributor.rb +60 -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 +101 -0
- data/lib/rbook/onix/product.rb +188 -0
- data/lib/rbook/onix/sales_restriction.rb +51 -0
- data/lib/rbook/onix/supply_detail.rb +68 -0
- data/lib/rbook/onix/xchar.rb +98 -0
- data/lib/rbook/titlepage.rb +96 -0
- data/lib/rbook/titlepage/TitleQueryClient.rb +62 -0
- data/lib/rbook/titlepage/titlepage_driver.rb +134 -0
- data/lib/rbook/titlepage/titlepage_utils.rb +374 -0
- data/lib/rbook/www.rb +172 -0
- data/lib/rbook/www/aau_scraper.rb +76 -0
- data/lib/rbook/www/amazon_uk_scraper.rb +44 -0
- data/lib/rbook/www/base.rb +87 -0
- data/lib/rbook/www/harper_au_scraper.rb +56 -0
- data/lib/rbook/www/harper_us_scraper.rb +55 -0
- data/lib/rbook/www/hha_scraper.rb +50 -0
- data/lib/rbook/www/macmillan_scraper.rb +62 -0
- data/lib/rbook/www/orbis_scraper.rb +48 -0
- data/lib/rbook/www/oup_scraper.rb +64 -0
- data/lib/rbook/www/paulist_scraper.rb +53 -0
- data/lib/rbook/www/pearson_au_scraper.rb +52 -0
- data/lib/rbook/www/penguin_scraper.rb +45 -0
- data/lib/rbook/www/random_au_scraper.rb +90 -0
- data/lib/rbook/www/random_us_scraper.rb +59 -0
- data/lib/rbook/www/sas_scraper.rb +54 -0
- data/lib/rbook/www/unireps_scraper.rb +58 -0
- data/lib/rbook/www/wiley_us_scraper.rb +54 -0
- data/test/data/abingdon.xml +38931 -0
- data/test/data/augsburg.xml +39009 -0
- data/test/data/chalice.xml +10851 -0
- data/test/data/eerdsman.xml +36942 -0
- data/test/data/invalid_no_product.xml +9 -0
- data/test/data/not_xml.csv +1 -0
- data/test/data/single_product.xml +50 -0
- data/test/data/xml_not_onix.xml +7 -0
- data/test/mocks/titlepage_driver.rb +107 -0
- data/test/unit/bisac_test.rb +57 -0
- data/test/unit/isbn_test.rb +149 -0
- data/test/unit/onix/contributor_test.rb +50 -0
- data/test/unit/onix/message_test.rb +119 -0
- data/test/unit/onix/product_test.rb +101 -0
- data/test/unit/onix/sales_restriction_test.rb +48 -0
- data/test/unit/onix/supply_detail_test.rb +53 -0
- data/test/unit/onix/xchar_test.rb +37 -0
- data/test/unit/titlepage_test.rb +127 -0
- metadata +130 -0
data/lib/rbook/onix.rb
ADDED
@@ -0,0 +1,68 @@
|
|
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/isbn'
|
11
|
+
|
12
|
+
module RBook
|
13
|
+
|
14
|
+
# Ruby classes for working with ONIX files. Currently only supports a very limited
|
15
|
+
# subset of the ONIX specification, but the core attributes are there. More will be
|
16
|
+
# added over time.
|
17
|
+
#
|
18
|
+
# = Usage
|
19
|
+
#
|
20
|
+
# == Loading from an REXML document
|
21
|
+
#
|
22
|
+
# require 'rubygems'
|
23
|
+
# require 'rbook/onix'
|
24
|
+
# file = File.open("./onix_message.xml", "r")
|
25
|
+
# doc = REXML::Document.new(file)
|
26
|
+
# msg = Onix::Message.load_from_xmldoc(doc)
|
27
|
+
#
|
28
|
+
# puts msg.from_company
|
29
|
+
#
|
30
|
+
# == Creation
|
31
|
+
#
|
32
|
+
# require 'rubygems'
|
33
|
+
# require 'rbook/onix'
|
34
|
+
# msg = RBook::Onix::Message.new
|
35
|
+
# msg.from_company = 'XYZ Books'
|
36
|
+
# msg.from_name = 'Joe Blogs'
|
37
|
+
# msg.message_note = "A sample ONIX file"
|
38
|
+
#
|
39
|
+
# product = RBook::Onix::Product.new
|
40
|
+
# product.product_identifier = "020161622X"
|
41
|
+
# product.title = "Pragmatic Programmer"
|
42
|
+
# product.subtitle = "From Journeyman to Master"
|
43
|
+
# product.form = "BB"
|
44
|
+
# product.description = "A book about programming and stuff"
|
45
|
+
#
|
46
|
+
# contributor1 = RBook::Onix::Contributor.new
|
47
|
+
# contributor1.name_inverted = "Hunt, Andrew"
|
48
|
+
# contributor1.role = "A01"
|
49
|
+
# contributor1.sequence = "01"
|
50
|
+
# contributor2 = RBook::Onix::Contributor.new
|
51
|
+
# contributor2.name_inverted = "Thomas, David"
|
52
|
+
# contributor2.role = "A01"
|
53
|
+
# contributor2.sequence = "02"
|
54
|
+
# product.add_contributor(contributor1)
|
55
|
+
# product.add_contributor(contributor2)
|
56
|
+
#
|
57
|
+
# supply_detail = RBook::Onix::SupplyDetail.new
|
58
|
+
# supply_detail.supplier_name = "Rainbow Book Agencies"
|
59
|
+
# supply_detail.price = BigDecimal.new(29.95)
|
60
|
+
# supply_detail.availability = "CS"
|
61
|
+
# product.add_supply_detail(supply_detail)
|
62
|
+
#
|
63
|
+
# msg.add_product(product)
|
64
|
+
# puts msg.to_s
|
65
|
+
module Onix
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
module RBook
|
5
|
+
module Onix
|
6
|
+
|
7
|
+
class Contributor
|
8
|
+
attr_accessor :sequence_number, :role, :name, :name_inverted
|
9
|
+
|
10
|
+
# Attempts to create a contributor object using the supplied xml element
|
11
|
+
def Contributor.load_from_element(element)
|
12
|
+
raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
|
13
|
+
|
14
|
+
if REXML::XPath.first(element, '//Contributor').nil?
|
15
|
+
raise LoadError, 'supplied REXML document object does not appear contain a valid contributor fragment'
|
16
|
+
end
|
17
|
+
|
18
|
+
contributor = Contributor.new
|
19
|
+
|
20
|
+
tmp = REXML::XPath.first(element, '//Contributor/SequenceNumber')
|
21
|
+
contributor.sequence_number = tmp.text if tmp != nil
|
22
|
+
|
23
|
+
tmp = REXML::XPath.first(element, '//Contributor/ContributorRole')
|
24
|
+
contributor.role = tmp.text if tmp != nil
|
25
|
+
|
26
|
+
tmp = REXML::XPath.first(element, '//Contributor/PersonName')
|
27
|
+
contributor.name = tmp.text if tmp != nil
|
28
|
+
|
29
|
+
tmp = REXML::XPath.first(element, '//Contributor/PersonNameInverted')
|
30
|
+
contributor.name_inverted = tmp.text if tmp != nil
|
31
|
+
|
32
|
+
return contributor
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return an xml element representing this contributor
|
37
|
+
def to_element
|
38
|
+
raise 'Contributor must have a sequence number to create an element' if @sequence_number.nil?
|
39
|
+
raise 'Contributor must have a role to create an element' if @role.nil?
|
40
|
+
raise '' if @name_inverted.nil? && @name.nil?
|
41
|
+
|
42
|
+
contributor = REXML::Element.new('Contributor')
|
43
|
+
contributor.add_element('SequenceNumber').text = self.sequence_number
|
44
|
+
contributor.add_element('ContributorRole').text = self.role.to_xs
|
45
|
+
contributor.add_element('PersonName').text = name.to_xs unless self.name.nil?
|
46
|
+
contributor.add_element('PersonNameInverted').text = self.name_inverted.to_xs unless self.name_inverted.nil?
|
47
|
+
|
48
|
+
return contributor
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return an XML string representing this contributor
|
52
|
+
def to_s
|
53
|
+
tmp = to_element
|
54
|
+
output = ''
|
55
|
+
tmp.write(output, 0)
|
56
|
+
return output
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
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,101 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
module RBook
|
5
|
+
module Onix
|
6
|
+
|
7
|
+
class Message
|
8
|
+
attr_reader :products
|
9
|
+
attr_accessor :from_company, :from_person, :from_email, :message_note, :sent_date, :to_person, :to_company
|
10
|
+
|
11
|
+
VERSION = 0.1
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@ONIX_DTD_URL = "http://www.editeur.org/onix/2.1/reference/onix-international.dtd"
|
15
|
+
|
16
|
+
@products = []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Attempts to create a message object using thge supplied xml document
|
20
|
+
def Message.load_from_xmldoc(doc)
|
21
|
+
raise ArgumentError, 'load_from_xmldoc expects a REXML document object' unless doc.class == REXML::Document
|
22
|
+
if REXML::XPath.first(doc, '/ONIXMessage/').nil? ||
|
23
|
+
REXML::XPath.first(doc, '/ONIXMessage/Header').nil? ||
|
24
|
+
REXML::XPath.first(doc, '/ONIXMessage/Product').nil?
|
25
|
+
raise LoadError, 'supplied REXML document object does not appear to be a valid ONIX file'
|
26
|
+
end
|
27
|
+
|
28
|
+
msg = Onix::Message.new
|
29
|
+
|
30
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/FromCompany')
|
31
|
+
msg.from_company = tmpelement.text if tmpelement != nil
|
32
|
+
|
33
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/FromPerson')
|
34
|
+
msg.from_person = tmpelement.text if tmpelement != nil
|
35
|
+
|
36
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/FromEmail')
|
37
|
+
msg.from_email = tmpelement.text if tmpelement != nil
|
38
|
+
|
39
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/SentDate')
|
40
|
+
tmpdate = Date.civil(tmpelement.text[0,4].to_i, tmpelement.text[4,2].to_i, tmpelement.text[6,2].to_i) if tmpelement != nil
|
41
|
+
msg.sent_date = tmpdate if tmpdate != nil
|
42
|
+
|
43
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/ToCompany')
|
44
|
+
msg.to_company = tmpelement.text if tmpelement != nil
|
45
|
+
|
46
|
+
tmpelement = REXML::XPath.first(doc, '/ONIXMessage/Header/ToPerson')
|
47
|
+
msg.to_person = tmpelement.text if tmpelement != nil
|
48
|
+
|
49
|
+
products = REXML::XPath.each(doc, '/ONIXMessage/Product') { |product|
|
50
|
+
msg.add_product(Onix::Product.load_from_element(product))
|
51
|
+
}
|
52
|
+
|
53
|
+
return msg
|
54
|
+
end
|
55
|
+
|
56
|
+
# Adds a new product to this message
|
57
|
+
def add_product(product)
|
58
|
+
raise ArgumentError, 'Argument must be a Onix::Product' if product.class != Onix::Product
|
59
|
+
@products << product
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns an XML string representing this message
|
63
|
+
def to_s
|
64
|
+
doc = to_xml
|
65
|
+
output = ''
|
66
|
+
doc.write(output, 0)
|
67
|
+
return output
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns an XML document representing this message
|
71
|
+
def to_xml
|
72
|
+
raise 'from_compnay must be set to create an onix message' if from_company == nil
|
73
|
+
raise 'from_person must be set to create an onix message' if from_person == nil
|
74
|
+
raise 'There must be at least 1 product to burn' if @products.size < 1
|
75
|
+
|
76
|
+
doc = REXML::Document.new
|
77
|
+
doc << REXML::XMLDecl.new
|
78
|
+
doc << REXML::DocType.new('ONIXMessage', "SYSTEM \"#{@ONIX_DTD_URL}\"")
|
79
|
+
msg = doc.add_element('ONIXMessage')
|
80
|
+
header = msg.add_element('Header')
|
81
|
+
header.add_element('FromCompany').text = from_company.to_xs
|
82
|
+
header.add_element('FromPerson').text = from_person.to_xs
|
83
|
+
header.add_element('FromEmail').text = from_email.to_xs unless from_email.nil?
|
84
|
+
header.add_element('MessageNote').text = message_note.to_xs unless message_note.nil?
|
85
|
+
header.add_element('ToCompany').text = to_company.to_xs unless to_company.nil?
|
86
|
+
header.add_element('ToPerson').text = to_person.to_xs unless to_person.nil?
|
87
|
+
|
88
|
+
now = Time.now
|
89
|
+
header.add_element('SentDate').text = "%.4d%.2d%.2d" % [ now.year, now.month, now.day ]
|
90
|
+
|
91
|
+
@products.each do |product|
|
92
|
+
prod = msg.add_element(product.to_element)
|
93
|
+
end
|
94
|
+
|
95
|
+
return doc
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
module RBook
|
5
|
+
module Onix
|
6
|
+
class Product
|
7
|
+
|
8
|
+
attr_accessor :record_reference, :notification_type, :product_identifier, :title, :subtitle, :pages, :publication_date, :price, :description, :form, :bicmainsubject, :publisher, :supplier, :website, :edition
|
9
|
+
attr_reader :contributors, :sales_restrictions, :supply_details
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@contributors = []
|
13
|
+
@supply_details = []
|
14
|
+
@sales_restrictions = []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Attempts to create a product object using the supplied xml element
|
18
|
+
def Product.load_from_element(element)
|
19
|
+
raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
|
20
|
+
|
21
|
+
if REXML::XPath.first(element, '//Product').nil?
|
22
|
+
raise LoadError, 'supplied REXML document object does not appear contain a valid product fragment'
|
23
|
+
end
|
24
|
+
|
25
|
+
product = Product.new
|
26
|
+
|
27
|
+
tmp = REXML::XPath.first(element, '//Product/RecordReference')
|
28
|
+
product.record_reference = tmp.text if tmp != nil
|
29
|
+
|
30
|
+
tmp = REXML::XPath.first(element, '//Product/NotificationType')
|
31
|
+
product.notification_type = tmp.text if tmp != nil
|
32
|
+
|
33
|
+
# TODO: load ProductIdentifier from the fragment
|
34
|
+
|
35
|
+
tmp = REXML::XPath.first(element, '//Product/ProductForm')
|
36
|
+
product.form = tmp.text if tmp != nil
|
37
|
+
|
38
|
+
tmp = REXML::XPath.first(element, '//Product/NumberOfPages')
|
39
|
+
product.pages = tmp.text if tmp != nil
|
40
|
+
|
41
|
+
tmp = REXML::XPath.first(element, '//Product/BICMainSubject')
|
42
|
+
product.bicmainsubject = tmp.text if tmp != nil
|
43
|
+
|
44
|
+
tmp = REXML::XPath.first(element, '//Product/DistinctiveTitle')
|
45
|
+
if !tmp.nil?
|
46
|
+
product.title = tmp.text
|
47
|
+
tmp = REXML::XPath.first(element, '//Product/Subtitle') if !tmp.nil?
|
48
|
+
product.subtitle = tmp.text
|
49
|
+
else
|
50
|
+
tmp = REXML::XPath.first(element, '//Product/Title/TitleText')
|
51
|
+
product.title = tmp.text unless tmp.nil?
|
52
|
+
tmp = REXML::XPath.first(element, '//Product/Title/Subtitle')
|
53
|
+
product.subtitle = tmp.text unless tmp.nil?
|
54
|
+
end
|
55
|
+
|
56
|
+
tmp = REXML::XPath.first(element, '//Product/EditionNumber')
|
57
|
+
product.edition = tmp.text if tmp != nil
|
58
|
+
|
59
|
+
tmp = REXML::XPath.first(element, '//Product/PublicationDate')
|
60
|
+
tmpdate = Date.civil(tmp.text[0,4].to_i, tmp.text[4,2].to_i, tmp.text[6,2].to_i) if tmp != nil
|
61
|
+
product.publication_date = tmpdate if tmpdate != nil
|
62
|
+
|
63
|
+
tmp = REXML::XPath.first(element, '//Product/Publisher/PublisherName')
|
64
|
+
product.publisher = tmp.text if tmp != nil
|
65
|
+
|
66
|
+
REXML::XPath.each(element, '//Product/Contributor') { |contributor|
|
67
|
+
product.add_contributor(Onix::Contributor.load_from_element(contributor))
|
68
|
+
}
|
69
|
+
|
70
|
+
REXML::XPath.each(element, '//Product/SupplyDetail') { |detail|
|
71
|
+
product.add_supply_detail(Onix::SupplyDetail.load_from_element(detail))
|
72
|
+
}
|
73
|
+
|
74
|
+
return product
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add a new contributor to this product
|
78
|
+
def add_contributor(newAuthor)
|
79
|
+
raise ArgumentError, 'Argument to add_contributor must be an ONIX::Contributor' if newAuthor.class != Contributor
|
80
|
+
@contributors << newAuthor
|
81
|
+
end
|
82
|
+
|
83
|
+
# Add a new contributor to this product
|
84
|
+
def add_sales_restriction(restriction)
|
85
|
+
raise ArgumentError, 'Argument to add_sales_restriction must be an ONIX::SalesRestriction' if restriction.class != SalesRestriction
|
86
|
+
@sales_restrictions << restriction
|
87
|
+
end
|
88
|
+
|
89
|
+
# Add a new contributor to this product
|
90
|
+
def add_supply_detail(detail)
|
91
|
+
raise ArgumentError, 'Argument to add_supply_detail must be an ONIX::SupplyDetail' if detail.class != SupplyDetail
|
92
|
+
@supply_details << detail
|
93
|
+
end
|
94
|
+
|
95
|
+
# Return an xml element representing this contributor
|
96
|
+
def to_element
|
97
|
+
raise 'product_identifier must be set' if self.product_identifier.nil?
|
98
|
+
|
99
|
+
product = REXML::Element.new('Product')
|
100
|
+
|
101
|
+
if self.record_reference
|
102
|
+
product.add_element('RecordReference').text = self.record_reference
|
103
|
+
else
|
104
|
+
product.add_element('RecordReference').text = self.product_identifier
|
105
|
+
end
|
106
|
+
|
107
|
+
product.add_element('NotificationType').text = '03'
|
108
|
+
|
109
|
+
product_identifier = REXML::Element.new('ProductIdentifier')
|
110
|
+
if ISBN::valid_isbn13?(self.product_identifier)
|
111
|
+
product_identifier.add_element('ProductIDType').text = '03'
|
112
|
+
elsif ISBN::valid_isbn10?(self.product_identifier)
|
113
|
+
product_identifier.add_element('ProductIDType').text = '02'
|
114
|
+
else
|
115
|
+
product_identifier.add_element('ProductIDType').text = '01'
|
116
|
+
end
|
117
|
+
product_identifier.add_element('IDValue').text = self.product_identifier.to_xs
|
118
|
+
product.add_element(product_identifier)
|
119
|
+
|
120
|
+
if form != nil
|
121
|
+
product.add_element('ProductForm').text = self.form.to_xs
|
122
|
+
end
|
123
|
+
|
124
|
+
product.add_element('NoSeries')
|
125
|
+
|
126
|
+
title = REXML::Element.new('Title')
|
127
|
+
title.add_element('TitleType').text = '01'
|
128
|
+
title.add_element('TitleText').text = self.title.to_xs unless self.title.nil?
|
129
|
+
title.add_element('Subtitle').text = self.subtitle.to_xs unless self.subtitle.nil?
|
130
|
+
product.add_element(title)
|
131
|
+
|
132
|
+
if website != nil
|
133
|
+
product_website = REXML::Element.new('Website')
|
134
|
+
product_website.add_element('WebsiteLink').text = self.website.to_xs
|
135
|
+
product.add_element(product_website)
|
136
|
+
end
|
137
|
+
|
138
|
+
contributors.each do |contributor|
|
139
|
+
product.add_element(contributor.to_element)
|
140
|
+
end
|
141
|
+
|
142
|
+
product.add_element('NoEdition')
|
143
|
+
|
144
|
+
product.add_element('NumberOfPages').text = self.pages.to_s unless self.pages.nil?
|
145
|
+
|
146
|
+
if bicmainsubject != nil
|
147
|
+
product.add_element('BICMainSubject').text = self.bicmainsubject.to_xs
|
148
|
+
end
|
149
|
+
|
150
|
+
if description != nil
|
151
|
+
other_text = REXML::Element.new('OtherText')
|
152
|
+
other_text.add_element('TextTypeCode').text = '01'
|
153
|
+
other_text.add_element('Text').text = self.description.to_xs
|
154
|
+
product.add_element(other_text)
|
155
|
+
end
|
156
|
+
|
157
|
+
if publisher != nil
|
158
|
+
publisher = REXML::Element.new('Publisher')
|
159
|
+
publisher.add_element('PublishingRole').text = '01'
|
160
|
+
publisher.add_element('PublisherName').text = self.publisher.to_xs
|
161
|
+
product.add_element(publisher)
|
162
|
+
end
|
163
|
+
|
164
|
+
supply_details.each do |detail|
|
165
|
+
product.add_element(detail.to_element)
|
166
|
+
end
|
167
|
+
|
168
|
+
sales_restrictions.each do |restriction|
|
169
|
+
product.add_element(restriction.to_element)
|
170
|
+
end
|
171
|
+
|
172
|
+
if publication_date != nil
|
173
|
+
product.add_element('PublicationDate').text = "%.4d%.2d%.2d" % [ publication_date.year, publication_date.month, publication_date.day ]
|
174
|
+
end
|
175
|
+
|
176
|
+
return product
|
177
|
+
end
|
178
|
+
|
179
|
+
# return an XML string representing this contributor
|
180
|
+
def to_s
|
181
|
+
output = ''
|
182
|
+
to_element.write(output, 0)
|
183
|
+
return output
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
end
|