rbook-onix 0.5.2 → 0.6.0
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/Rakefile +3 -1
- data/examples/header.xml +55 -0
- data/examples/message.rb +8 -0
- data/examples/stream_reader.rb +2 -1
- data/lib/rbook/onix.rb +1 -0
- data/lib/rbook/onix/contributor.rb +36 -38
- data/lib/rbook/onix/message.rb +68 -67
- data/lib/rbook/onix/product.rb +112 -108
- data/lib/rbook/onix/sales_restriction.rb +26 -31
- data/lib/rbook/onix/stream_reader.rb +32 -10
- data/lib/rbook/onix/supply_detail.rb +47 -51
- data/specs/contributor_with_data_spec.rb +13 -5
- data/specs/data/2_ids.xml +55 -0
- data/specs/data/leading_garbage.xml +70 -0
- data/specs/data/truncated.xml +80 -0
- data/specs/data/with_ampersands.xml +111 -0
- data/specs/message_class_spec.rb +10 -3
- data/specs/message_with_data_spec.rb +25 -4
- data/specs/product_class_spec.rb +10 -0
- data/specs/product_with_data_spec.rb +30 -9
- data/specs/sales_restriction_with_data_spec.rb +12 -5
- data/specs/stream_reader_spec.rb +57 -0
- data/specs/supply_detail_with_data_spec.rb +18 -9
- metadata +51 -27
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'rake/testtask'
|
|
6
6
|
require "rake/gempackagetask"
|
7
7
|
require 'spec/rake/spectask'
|
8
8
|
|
9
|
-
PKG_VERSION = "0.
|
9
|
+
PKG_VERSION = "0.6.0"
|
10
10
|
PKG_NAME = "rbook-onix"
|
11
11
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
12
12
|
RUBYFORGE_PROJECT = 'rbook'
|
@@ -80,6 +80,8 @@ spec = Gem::Specification.new do |spec|
|
|
80
80
|
spec.rdoc_options << '--title' << 'onix Documentation' <<
|
81
81
|
'--main' << 'README' << '-q'
|
82
82
|
spec.add_dependency('rbook-isbn', '>= 1.0')
|
83
|
+
spec.add_dependency('hpricot', '>= 0.6')
|
84
|
+
spec.add_dependency('builder', '>= 2.1.2')
|
83
85
|
spec.author = "James Healy"
|
84
86
|
spec.email = "jimmy@deefa.com"
|
85
87
|
spec.rubyforge_project = "rbook"
|
data/examples/header.xml
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
<?xml version='1.0'?>
|
2
|
+
<!DOCTYPE ONIXMessage SYSTEM "http://www.editeur.org/onix/2.1/reference/onix-international.dtd">
|
3
|
+
<ONIXMessage>
|
4
|
+
<Header>
|
5
|
+
<FromCompany>Chalice</FromCompany>
|
6
|
+
<FromPerson>James Healy</FromPerson>
|
7
|
+
<SentDate>20060521</SentDate>
|
8
|
+
</Header>
|
9
|
+
<Product>
|
10
|
+
<RecordReference>0827200528</RecordReference>
|
11
|
+
<NotificationType>03</NotificationType>
|
12
|
+
<ProductIdentifier>
|
13
|
+
<ProductIDType>02</ProductIDType>
|
14
|
+
<IDValue>0827200528</IDValue>
|
15
|
+
</ProductIdentifier>
|
16
|
+
<ProductForm>BA</ProductForm>
|
17
|
+
<NoSeries/>
|
18
|
+
<Title>
|
19
|
+
<TitleType>01</TitleType>
|
20
|
+
<TitleText>And Their Eyes Are Opened</TitleText>
|
21
|
+
<Subtitle>Story Sermons Embracing the World</Subtitle>
|
22
|
+
</Title>
|
23
|
+
<Contributor>
|
24
|
+
<SequenceNumber>0</SequenceNumber>
|
25
|
+
<ContributorRole>A01</ContributorRole>
|
26
|
+
<PersonNameInverted>Healy, James</PersonNameInverted>
|
27
|
+
</Contributor>
|
28
|
+
<NoEdition/>
|
29
|
+
<BICMainSubject>YFH</BICMainSubject>
|
30
|
+
<MediaFile>
|
31
|
+
<MediaFileTypeCode>04</MediaFileTypeCode>
|
32
|
+
<MediaFileLinkTypeCode>01</MediaFileLinkTypeCode>
|
33
|
+
<MediaFileLink>http://www.example.com/0827200528.jpg</MediaFileLink>
|
34
|
+
</MediaFile>
|
35
|
+
<NumberOfPages>0</NumberOfPages>
|
36
|
+
<Publisher>
|
37
|
+
<PublishingRole>01</PublishingRole>
|
38
|
+
<PublisherName>Chalice</PublisherName>
|
39
|
+
</Publisher>
|
40
|
+
<PublicationDate>20050303</PublicationDate>
|
41
|
+
<SalesRestriction>
|
42
|
+
<SalesRestrictionType>00</SalesRestrictionType>
|
43
|
+
<SalesRestrictionDetail>Unknown</SalesRestrictionDetail>
|
44
|
+
</SalesRestriction>
|
45
|
+
<SupplyDetail>
|
46
|
+
<SupplierName>Chalice</SupplierName>
|
47
|
+
<AvailabilityCode>CS</AvailabilityCode>
|
48
|
+
<IntermediaryAvailabilityCode>99</IntermediaryAvailabilityCode>
|
49
|
+
<Price>
|
50
|
+
<PriceTypeCode>02</PriceTypeCode>
|
51
|
+
<PriceAmount>29.95</PriceAmount>
|
52
|
+
</Price>
|
53
|
+
</SupplyDetail>
|
54
|
+
</Product>
|
55
|
+
</ONIXMessage>
|
data/examples/message.rb
ADDED
data/examples/stream_reader.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
2
2
|
|
3
|
+
require 'rubygems'
|
3
4
|
require 'rbook/onix'
|
4
5
|
|
5
|
-
reader = RBook::Onix::StreamReader.new(File.dirname(__FILE__)+"/../specs/data/
|
6
|
+
reader = RBook::Onix::StreamReader.new(File.dirname(__FILE__)+"/../specs/data/eerdsman.xml")
|
6
7
|
counter = 0
|
7
8
|
|
8
9
|
reader.each do |product|
|
data/lib/rbook/onix.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'rexml/document'
|
2
|
+
require 'hpricot'
|
3
|
+
require 'active_support'
|
2
4
|
|
3
5
|
module RBook
|
4
6
|
module Onix
|
@@ -6,59 +8,55 @@ module Onix
|
|
6
8
|
class Contributor
|
7
9
|
attr_accessor :sequence_number, :role, :name, :name_inverted
|
8
10
|
|
9
|
-
|
10
|
-
|
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
|
-
|
11
|
+
def Contributor.load_from_string(str)
|
12
|
+
doc = Hpricot::XML(str)
|
17
13
|
contributor = Contributor.new
|
18
14
|
|
19
|
-
tmp =
|
20
|
-
contributor.sequence_number = tmp.
|
15
|
+
tmp = doc.search('//Contributor/sequencenumber')
|
16
|
+
contributor.sequence_number = tmp.inner_html unless tmp.inner_html.blank?
|
21
17
|
|
22
|
-
tmp =
|
23
|
-
contributor.role = tmp.
|
18
|
+
tmp = doc.search('//Contributor/contributorrole')
|
19
|
+
contributor.role = tmp.inner_html unless tmp.inner_html.blank?
|
24
20
|
|
25
|
-
tmp =
|
26
|
-
contributor.name = tmp.
|
21
|
+
tmp = doc.search('//Contributor/personname')
|
22
|
+
contributor.name = tmp.inner_html unless tmp.inner_html.blank?
|
27
23
|
|
28
|
-
tmp =
|
29
|
-
contributor.name_inverted = tmp.
|
24
|
+
tmp = doc.search('//Contributor/personnameinverted')
|
25
|
+
contributor.name_inverted = tmp.inner_html unless tmp.inner_html.blank?
|
30
26
|
|
31
27
|
return contributor
|
32
|
-
|
33
28
|
end
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
raise '
|
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?
|
29
|
+
|
30
|
+
# Attempts to create a contributor object using the supplied xml element
|
31
|
+
# WARNING: deprecated method
|
32
|
+
def Contributor.load_from_element(element)
|
33
|
+
raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
|
46
34
|
|
47
|
-
|
35
|
+
if REXML::XPath.first(element, '//Contributor').nil?
|
36
|
+
raise LoadError, 'supplied REXML document object does not appear contain a valid contributor fragment'
|
37
|
+
end
|
38
|
+
|
39
|
+
self.load_from_string(element.to_s)
|
48
40
|
end
|
49
41
|
|
50
42
|
# Return an XML string representing this contributor
|
51
43
|
def to_s
|
52
|
-
|
44
|
+
raise 'Contributor must have a sequence number to create an element' if @sequence_number.nil?
|
45
|
+
raise 'Contributor must have a role to create an element' if @role.nil?
|
46
|
+
raise '' if @name_inverted.nil? && @name.nil?
|
47
|
+
|
48
|
+
builder = Builder::XmlMarkup.new(:indent => 2)
|
53
49
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
to_element.write(output, 0)
|
50
|
+
builder.Contributor do |c|
|
51
|
+
c.SequenceNumber self.sequence_number
|
52
|
+
c.ContributorRole self.role
|
53
|
+
c.PersonName self.name unless self.name.nil?
|
54
|
+
c.PersonNameInverted self.name_inverted unless self.name_inverted.nil?
|
60
55
|
end
|
61
|
-
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_element
|
59
|
+
REXML::Document.new(to_s).root
|
62
60
|
end
|
63
61
|
end
|
64
62
|
end
|
data/lib/rbook/onix/message.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rexml/document'
|
2
|
+
require 'rexml/formatters/transitive'
|
2
3
|
|
3
4
|
module RBook
|
4
5
|
module Onix
|
@@ -21,52 +22,65 @@ module RBook
|
|
21
22
|
# Attempts to create a message object using thge supplied xml string
|
22
23
|
def self.load_from_string(str)
|
23
24
|
self.check_ruby_version
|
25
|
+
|
26
|
+
# attempt to pass the string through REXML, which will auto convert it
|
27
|
+
# to UTF-8 for us. If the file is invalid XML, then still attempt to use
|
28
|
+
# HPricot to parse it, as some data may be extractable
|
24
29
|
begin
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
raise LoadError, e.message
|
30
|
+
rexml_doc = REXML::Document.new(str)
|
31
|
+
rescue REXML::ParseException
|
32
|
+
# do nothin
|
29
33
|
end
|
30
|
-
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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'
|
35
|
+
if rexml_doc
|
36
|
+
doc = Hpricot::XML(rexml_doc.to_s)
|
37
|
+
else
|
38
|
+
doc = Hpricot::XML(str)
|
40
39
|
end
|
41
40
|
|
42
41
|
msg = Onix::Message.new
|
43
42
|
|
44
|
-
|
45
|
-
msg.from_company =
|
43
|
+
tmp = doc.search('/ONIXMessage/Header/FromCompany')
|
44
|
+
msg.from_company = tmp.inner_html unless tmp.inner_html.blank?
|
46
45
|
|
47
|
-
|
48
|
-
msg.from_person =
|
46
|
+
tmp = doc.search('/ONIXMessage/Header/FromPerson')
|
47
|
+
msg.from_person = tmp.inner_html unless tmp.inner_html.blank?
|
49
48
|
|
50
|
-
|
51
|
-
msg.from_email =
|
49
|
+
tmp = doc.search('/ONIXMessage/Header/FromEmail')
|
50
|
+
msg.from_email = tmp.inner_html unless tmp.inner_html.blank?
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
tmp = doc.search('/ONIXMessage/Header/SentDate')
|
53
|
+
if !tmp.inner_html.blank? && tmp.inner_html.length == 8
|
54
|
+
tmpdate = Date.civil(tmp.inner_html[0,4].to_i, tmp.inner_html[4,2].to_i, tmp.inner_html[6,2].to_i)
|
55
|
+
msg.sent_date = tmpdate unless tmpdate.nil?
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
msg.to_company =
|
58
|
+
tmp = doc.search('/ONIXMessage/Header/ToCompany')
|
59
|
+
msg.to_company = tmp.inner_html unless tmp.inner_html.blank?
|
59
60
|
|
60
|
-
|
61
|
-
msg.to_person =
|
61
|
+
tmp = doc.search('/ONIXMessage/Header/ToPerson')
|
62
|
+
msg.to_person = tmp.inner_html unless tmp.inner_html.blank?
|
62
63
|
|
63
|
-
|
64
|
-
msg.add_product(Onix::Product.
|
65
|
-
|
64
|
+
doc.search('/ONIXMessage/Product').each do |product|
|
65
|
+
msg.add_product(Onix::Product.load_from_string("<Product>#{product}</Product>"))
|
66
|
+
end
|
66
67
|
|
67
68
|
return msg
|
68
69
|
end
|
69
70
|
|
71
|
+
# Attempts to create a message object using thge supplied xml document
|
72
|
+
def self.load_from_xmldoc(doc)
|
73
|
+
self.check_ruby_version
|
74
|
+
raise ArgumentError, 'load_from_xmldoc expects a REXML document object' unless doc.class == REXML::Document
|
75
|
+
if REXML::XPath.first(doc, '/ONIXMessage/').nil? ||
|
76
|
+
REXML::XPath.first(doc, '/ONIXMessage/Header').nil? ||
|
77
|
+
REXML::XPath.first(doc, '/ONIXMessage/Product').nil?
|
78
|
+
raise LoadError, 'supplied REXML document object does not appear to be a valid ONIX file'
|
79
|
+
end
|
80
|
+
|
81
|
+
self.load_from_string(doc.to_s)
|
82
|
+
end
|
83
|
+
|
70
84
|
# Adds a new product to this message
|
71
85
|
def add_product(product)
|
72
86
|
raise ArgumentError, 'Argument must be a Onix::Product' if product.class != Onix::Product
|
@@ -75,51 +89,38 @@ module RBook
|
|
75
89
|
|
76
90
|
# Returns an XML string representing this message
|
77
91
|
def to_s
|
78
|
-
doc = to_xml
|
79
|
-
output = ''
|
80
|
-
# stupid hack, because the ruby release mangers imported a broken REXML for this patchset
|
81
|
-
if RUBY_VERSION == "1.8.6" && (RUBY_PATCHLEVEL == 110 || RUBY_PATCHLEVEL == 111)
|
82
|
-
doc.write(output,-1)
|
83
|
-
else
|
84
|
-
doc.write(output,0)
|
85
|
-
end
|
86
|
-
return output
|
87
|
-
end
|
88
|
-
|
89
|
-
def header
|
90
92
|
raise 'from_compnay must be set to create an onix message' if from_company == nil
|
91
93
|
raise 'from_person must be set to create an onix message' if from_person == nil
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
return header
|
94
|
+
raise 'at least one product must be added create an onix message' if @products.size == 0
|
95
|
+
|
96
|
+
builder = Builder::XmlMarkup.new(:indent => 2)
|
97
|
+
builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
98
|
+
builder.declare! :DOCTYPE, :ONIXMessage, :SYSTEM, "http://www.editeur.org/onix/2.1/reference/onix-international.dtd"
|
99
|
+
builder.ONIXMessage do |msg|
|
100
|
+
msg << self.header
|
101
|
+
@products.each do |product|
|
102
|
+
msg << product.to_s
|
103
|
+
end
|
104
|
+
end
|
104
105
|
end
|
105
|
-
|
106
|
-
# Returns an XML document representing this message
|
107
|
-
def to_xml
|
108
|
-
raise 'There must be at least 1 product to burn' if @products.size < 1
|
109
106
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
msg = doc.add_element('ONIXMessage')
|
114
|
-
msg.add_element(header)
|
107
|
+
def to_xml
|
108
|
+
REXML::Document.new(to_s)
|
109
|
+
end
|
115
110
|
|
116
|
-
|
117
|
-
|
111
|
+
def header
|
112
|
+
builder = Builder::XmlMarkup.new(:indent => 2)
|
113
|
+
builder.Header do |h|
|
114
|
+
h.FromCompany @from_company if @from_company
|
115
|
+
h.FromPerson @from_person if @from_person
|
116
|
+
h.FromEmail @from_email if @from_email
|
117
|
+
h.message_note @message_note if @message_note
|
118
|
+
h.SentDate @sent_date if @sent_date
|
119
|
+
h.ToPerson @to_person if @to_person
|
120
|
+
h.ToCompany @to_company if @to_company
|
118
121
|
end
|
119
|
-
|
120
|
-
return doc
|
121
122
|
end
|
122
|
-
|
123
|
+
|
123
124
|
end
|
124
125
|
|
125
126
|
end
|
data/lib/rbook/onix/product.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'rexml/document'
|
2
|
+
require 'hpricot'
|
3
|
+
require 'active_support'
|
2
4
|
|
3
5
|
module RBook
|
4
6
|
module Onix
|
@@ -16,76 +18,88 @@ module RBook
|
|
16
18
|
@sales_restrictions = []
|
17
19
|
end
|
18
20
|
|
19
|
-
# Attempts to create a product object using the supplied xml
|
20
|
-
def Product.
|
21
|
-
|
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
|
-
|
21
|
+
# Attempts to create a product object using the supplied xml fragment
|
22
|
+
def Product.load_from_string(str)
|
23
|
+
doc = Hpricot::XML(str)
|
24
|
+
|
27
25
|
product = Product.new
|
28
26
|
|
29
|
-
tmp =
|
30
|
-
product.record_reference = tmp.
|
27
|
+
tmp = doc.search("//Product/recordreference")
|
28
|
+
product.record_reference = tmp.inner_html unless tmp.inner_html.blank?
|
31
29
|
|
32
|
-
tmp =
|
33
|
-
product.notification_type = tmp.
|
30
|
+
tmp = doc.search("//Product/notificationtype")
|
31
|
+
product.notification_type = tmp.inner_html unless tmp.inner_html.blank?
|
34
32
|
|
35
|
-
tmp =
|
36
|
-
product.product_identifier = tmp.
|
33
|
+
tmp = doc.search("//Product/productidentifier/idvalue").first
|
34
|
+
product.product_identifier = tmp.inner_html unless tmp.inner_html.blank?
|
37
35
|
|
38
|
-
tmp =
|
39
|
-
product.form = tmp.
|
36
|
+
tmp = doc.search("//Product/productform")
|
37
|
+
product.form = tmp.inner_html unless tmp.inner_html.blank?
|
40
38
|
|
41
|
-
tmp =
|
42
|
-
product.pages = tmp.
|
39
|
+
tmp = doc.search("//Product/numberofpages")
|
40
|
+
product.pages = tmp.inner_html unless tmp.inner_html.blank?
|
43
41
|
|
44
|
-
tmp =
|
45
|
-
product.bicmainsubject = tmp.
|
42
|
+
tmp = doc.search("//Product/bicmainsubject")
|
43
|
+
product.bicmainsubject = tmp.inner_html unless tmp.inner_html.blank?
|
46
44
|
|
47
|
-
|
48
|
-
type =
|
45
|
+
doc.search("//Product/mediafile").each do |mediafile|
|
46
|
+
type = doc.search('//Product/mediafile/mediafiletypecode')
|
49
47
|
# cover image
|
50
|
-
if type.
|
51
|
-
url =
|
52
|
-
product.cover_image = url.
|
48
|
+
if type.inner_html.eql?("04")
|
49
|
+
url = doc.search('//Product/mediafile/mediafilelink')
|
50
|
+
product.cover_image = url.inner_html unless url.inner_html.blank?
|
53
51
|
end
|
54
|
-
|
52
|
+
end
|
55
53
|
|
56
|
-
tmp =
|
57
|
-
if !tmp.
|
58
|
-
product.title = tmp.
|
59
|
-
tmp =
|
60
|
-
product.subtitle = tmp.
|
54
|
+
tmp = doc.search("//Product/distinctivetitle")
|
55
|
+
if !tmp.inner_html.blank?
|
56
|
+
product.title = tmp.inner_html
|
57
|
+
tmp = doc.search('//Product/subtitle')
|
58
|
+
product.subtitle = tmp.inner_html unless tmp.inner_html.blank?
|
61
59
|
else
|
62
|
-
tmp =
|
63
|
-
product.title = tmp.
|
64
|
-
tmp =
|
65
|
-
product.subtitle = tmp.
|
60
|
+
tmp = doc.search('//Product/title/titletext')
|
61
|
+
product.title = tmp.inner_html unless tmp.inner_html.blank?
|
62
|
+
tmp = doc.search('//Product/title/subtitle')
|
63
|
+
product.subtitle = tmp.inner_html unless tmp.inner_html.blank?
|
66
64
|
end
|
67
65
|
|
68
|
-
tmp =
|
69
|
-
product.edition = tmp.
|
66
|
+
tmp = doc.search('//Product/editionnumber')
|
67
|
+
product.edition = tmp.inner_html unless tmp.inner_html.blank?
|
70
68
|
|
71
|
-
tmp =
|
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
|
69
|
+
tmp = doc.search('//Product/publicationdate')
|
74
70
|
|
75
|
-
tmp
|
76
|
-
|
71
|
+
if !tmp.inner_html.blank? && tmp.inner_html.length == 8
|
72
|
+
tmpdate = Date.civil(tmp.inner_html[0,4].to_i, tmp.inner_html[4,2].to_i, tmp.inner_html[6,2].to_i)
|
73
|
+
product.publication_date = tmpdate unless tmpdate.nil?
|
74
|
+
end
|
77
75
|
|
78
|
-
|
79
|
-
|
80
|
-
}
|
76
|
+
tmp = doc.search('//Product/publisher/publishername')
|
77
|
+
product.publisher = tmp.inner_html unless tmp.inner_html.blank?
|
81
78
|
|
82
|
-
|
83
|
-
product.
|
84
|
-
|
79
|
+
doc.search('//Product/contributor').each do |contributor|
|
80
|
+
product.add_contributor(Onix::Contributor.load_from_string("<contributor>#{contributor}</contributor>"))
|
81
|
+
end
|
82
|
+
|
83
|
+
doc.search('//Product/supplydetail').each do |detail|
|
84
|
+
product.add_supply_detail(Onix::SupplyDetail.load_from_string("<SupplyDetail>#{detail}</SupplyDetail>"
|
85
|
+
))
|
86
|
+
end
|
85
87
|
|
86
88
|
return product
|
87
89
|
end
|
88
90
|
|
91
|
+
# Attempts to create a product object using the supplied xml element
|
92
|
+
# WARNING: Deprecated method
|
93
|
+
def Product.load_from_element(element)
|
94
|
+
raise ArgumentError, 'load_from_element expects a REXML element object' unless element.class == REXML::Element
|
95
|
+
|
96
|
+
if REXML::XPath.first(element, '//Product').nil?
|
97
|
+
raise LoadError, 'supplied REXML document object does not appear contain a valid product fragment'
|
98
|
+
end
|
99
|
+
|
100
|
+
self.load_from_string(element.to_s)
|
101
|
+
end
|
102
|
+
|
89
103
|
# Add a new contributor to this product
|
90
104
|
def add_contributor(newAuthor)
|
91
105
|
raise ArgumentError, 'Argument to add_contributor must be an ONIX::Contributor' if newAuthor.class != Contributor
|
@@ -104,110 +118,100 @@ module RBook
|
|
104
118
|
@supply_details << detail
|
105
119
|
end
|
106
120
|
|
107
|
-
#
|
108
|
-
def
|
121
|
+
# return an XML string representing this contributor
|
122
|
+
def to_s
|
109
123
|
raise 'product_identifier must be set' if self.product_identifier.nil?
|
110
124
|
|
111
|
-
|
125
|
+
builder = Builder::XmlMarkup.new(:indent => 2)
|
126
|
+
builder.Product do |p|
|
112
127
|
|
113
|
-
if
|
114
|
-
|
128
|
+
if @record_reference
|
129
|
+
p.RecordReference self.record_reference
|
115
130
|
else
|
116
|
-
|
131
|
+
p.RecordReference self.product_identifier
|
117
132
|
end
|
118
133
|
|
119
|
-
|
134
|
+
p.NotificationType '03'
|
120
135
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
136
|
+
p.ProductIdentifier do |id|
|
137
|
+
if ISBN::valid_isbn13?(self.product_identifier)
|
138
|
+
p.ProductIDType '03'
|
139
|
+
elsif ISBN::valid_isbn10?(self.product_identifier)
|
140
|
+
p.ProductIDType '02'
|
141
|
+
else
|
142
|
+
p.ProductIDType '01'
|
143
|
+
end
|
144
|
+
p.IDValue self.product_identifier
|
128
145
|
end
|
129
|
-
product_identifier.add_element('IDValue').text = self.product_identifier.to_xs
|
130
|
-
product.add_element(product_identifier)
|
131
146
|
|
132
|
-
|
133
|
-
product.add_element('ProductForm').text = self.form.to_xs
|
134
|
-
end
|
147
|
+
p.ProductForm self.form
|
135
148
|
|
136
|
-
|
149
|
+
p.NoSeries
|
137
150
|
|
138
151
|
title = REXML::Element.new('Title')
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
152
|
+
p.Title do |t|
|
153
|
+
t.TitleType '01'
|
154
|
+
t.TitleText self.title unless self.title.nil?
|
155
|
+
t.Subtitle self.subtitle unless self.subtitle.nil?
|
156
|
+
end
|
143
157
|
|
144
158
|
if website != nil
|
145
|
-
|
146
|
-
|
147
|
-
|
159
|
+
p.Website do |w|
|
160
|
+
w.WebsiteLink self.website
|
161
|
+
end
|
148
162
|
end
|
149
163
|
|
150
164
|
unless cover_image.nil?
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
165
|
+
p.MediaFile do |m|
|
166
|
+
m.MediaFileTypeCode "04"
|
167
|
+
m.MediaFileLinkTypeCode "01"
|
168
|
+
m.MediaFileLink self.cover_image
|
169
|
+
end
|
156
170
|
end
|
157
171
|
|
158
172
|
contributors.each do |contributor|
|
159
|
-
|
173
|
+
p << contributor.to_s
|
160
174
|
end
|
161
175
|
|
162
|
-
|
176
|
+
p.NoEdition
|
163
177
|
|
164
|
-
|
178
|
+
p.NumberOfPages self.pages.to_s unless self.pages.nil?
|
165
179
|
|
166
180
|
if bicmainsubject != nil
|
167
|
-
|
181
|
+
p.BICMainSubject = self.bicmainsubject
|
168
182
|
end
|
169
183
|
|
170
184
|
if description != nil
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
185
|
+
p.OtherText do |t|
|
186
|
+
t.TextTypeCode '01'
|
187
|
+
t.Text self.description
|
188
|
+
end
|
175
189
|
end
|
176
190
|
|
177
191
|
if publisher != nil
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
192
|
+
p.Publisher do |pub|
|
193
|
+
pub.PublishingRole '01'
|
194
|
+
pub.PublisherName self.publisher
|
195
|
+
end
|
182
196
|
end
|
183
197
|
|
184
198
|
supply_details.each do |detail|
|
185
|
-
|
199
|
+
p << detail.to_s
|
186
200
|
end
|
187
201
|
|
188
202
|
sales_restrictions.each do |restriction|
|
189
|
-
|
203
|
+
p << restriction.to_s
|
190
204
|
end
|
191
205
|
|
192
206
|
if publication_date != nil
|
193
|
-
|
207
|
+
p.PublicationDate("%.4d%.2d%.2d" % [ publication_date.year, publication_date.month, publication_date.day ])
|
194
208
|
end
|
195
209
|
|
196
|
-
|
210
|
+
end
|
197
211
|
end
|
198
212
|
|
199
|
-
|
200
|
-
|
201
|
-
output = ''
|
202
|
-
|
203
|
-
# handle the REXML API change in 1.8.6.110. bah!
|
204
|
-
if RUBY_VERSION >= "1.8.6" && RUBY_PATCHLEVEL >= 110
|
205
|
-
formatter = REXML::Formatters::Pretty.new( 2 )
|
206
|
-
formatter.write( to_element , output )
|
207
|
-
else
|
208
|
-
to_element.write(output, 0)
|
209
|
-
end
|
210
|
-
return output
|
213
|
+
def to_element
|
214
|
+
REXML::Document.new(to_s).root
|
211
215
|
end
|
212
216
|
end
|
213
217
|
|