onix 0.4.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/CHANGELOG +30 -0
- data/README.rdoc +30 -0
- data/TODO +14 -0
- data/lib/onix.rb +57 -0
- data/lib/onix/addressee_identifier.rb +9 -0
- data/lib/onix/apa_product.rb +534 -0
- data/lib/onix/contributor.rb +20 -0
- data/lib/onix/date_type.rb +54 -0
- data/lib/onix/etext_type.rb +44 -0
- data/lib/onix/header.rb +31 -0
- data/lib/onix/imprint.rb +10 -0
- data/lib/onix/integer_type.rb +43 -0
- data/lib/onix/lists/product_availability.rb +30 -0
- data/lib/onix/lists/product_form.rb +97 -0
- data/lib/onix/media_file.rb +11 -0
- data/lib/onix/other_text.rb +12 -0
- data/lib/onix/price.rb +16 -0
- data/lib/onix/product.rb +30 -0
- data/lib/onix/product_identifier.rb +8 -0
- data/lib/onix/publisher.rb +11 -0
- data/lib/onix/reader.rb +124 -0
- data/lib/onix/sales_restriction.rb +7 -0
- data/lib/onix/sender_identifier.rb +9 -0
- data/lib/onix/simple_product.rb +41 -0
- data/lib/onix/stock.rb +10 -0
- data/lib/onix/subject.rb +11 -0
- data/lib/onix/supply_detail.rb +21 -0
- data/lib/onix/title.rb +10 -0
- data/lib/onix/two_digit_type.rb +57 -0
- data/lib/onix/website.rb +9 -0
- data/lib/onix/writer.rb +87 -0
- data/spec/header_spec.rb +111 -0
- data/spec/product_spec.rb +75 -0
- data/spec/reader_spec.rb +64 -0
- data/spec/writer_spec.rb +81 -0
- metadata +117 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module ONIX
|
4
|
+
# super class for some simplified ONIX::Product wrappers
|
5
|
+
class SimpleProduct
|
6
|
+
|
7
|
+
def initialize(product = nil)
|
8
|
+
@product = product || ::ONIX::Product.new
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
include Forwardable
|
14
|
+
|
15
|
+
def parse_file(filename)
|
16
|
+
self.new(::ONIX::Product.parse(File.read(filename)))
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(xml)
|
20
|
+
self.new(::ONIX::Product.parse(xml))
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def delegate(*args)
|
26
|
+
def_delegators :@product, *args
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def product
|
31
|
+
@product
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_xml
|
35
|
+
product.to_xml
|
36
|
+
end
|
37
|
+
|
38
|
+
# TODO: add method missing magic to proxy through to the underlying product?
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/lib/onix/stock.rb
ADDED
data/lib/onix/subject.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module ONIX
|
2
|
+
class Subject
|
3
|
+
include ROXML
|
4
|
+
|
5
|
+
xml_accessor :subject_scheme_id, :twodigit, :from => "SubjectSchemeIdentifier"
|
6
|
+
xml_accessor :subject_scheme_name, :from => "SubjectSchemeName"
|
7
|
+
xml_accessor :subject_scheme_version, :from => "SubjectSchemeVersion"
|
8
|
+
xml_accessor :subject_code, :from => "SubjectCode"
|
9
|
+
xml_accessor :subject_heading_text, :from => "SubjectHeadingText"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ONIX
|
2
|
+
class SupplyDetail
|
3
|
+
include ROXML
|
4
|
+
|
5
|
+
xml_accessor :supplier_ean_location_number, :from => "SupplierEANLocationNumber"
|
6
|
+
xml_accessor :supplier_san, :from => "SupplierSAN"
|
7
|
+
xml_accessor :supplier_name, :from => "SupplierName"
|
8
|
+
xml_accessor :telephone_number, :from => "TelephoneNumber"
|
9
|
+
xml_accessor :fax_number, :from => "FaxNumber"
|
10
|
+
xml_accessor :email_address, :from => "EmailAddress"
|
11
|
+
xml_accessor :websites, [ONIX::Website], :from => "Website"
|
12
|
+
xml_accessor :supplier_role, :twodigit, :from => "SupplierRole"
|
13
|
+
xml_accessor :supply_to_country, :from => "SupplyToCountry"
|
14
|
+
xml_accessor :supply_to_territory, :from => "SupplyToTerritory"
|
15
|
+
xml_accessor :availability_status_code, :twodigit, :from => "AvailabilityStatusCode"
|
16
|
+
xml_accessor :product_availability, :twodigit, :from => "ProductAvailability"
|
17
|
+
xml_accessor :stock, [ONIX::Stock], :from => "Stock"
|
18
|
+
xml_accessor :prices, [ONIX::Price], :from => "Price"
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/onix/title.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
module ONIX
|
3
|
+
|
4
|
+
# Internal class representing 2-digit XML content
|
5
|
+
#
|
6
|
+
# In context:
|
7
|
+
# <element attribute="XMLAttributeRef">
|
8
|
+
# XMLTwoDigitRef
|
9
|
+
# </element>
|
10
|
+
class TwoDigitType < ROXML::XMLRef # ::nodoc::
|
11
|
+
attr_reader :cdata, :content
|
12
|
+
|
13
|
+
def initialize(accessor, args, &block)
|
14
|
+
super(accessor, args, &block)
|
15
|
+
@content = args.content?
|
16
|
+
@cdata = args.cdata?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Updates the text in the given _xml_ block to
|
20
|
+
# the _value_ provided.
|
21
|
+
def update_xml(xml, value)
|
22
|
+
parent = wrap(xml)
|
23
|
+
value = value.to_i
|
24
|
+
if value < 10
|
25
|
+
value = "0#{value}"
|
26
|
+
elsif value < 100
|
27
|
+
value = value.to_s
|
28
|
+
else
|
29
|
+
value = "00"
|
30
|
+
end
|
31
|
+
add(parent.child_add(LibXML::XML::Node.new_element(name)), value)
|
32
|
+
xml
|
33
|
+
end
|
34
|
+
|
35
|
+
def value(xml)
|
36
|
+
if content
|
37
|
+
value = xml.content.to_i
|
38
|
+
else
|
39
|
+
child = xml.search(name).first
|
40
|
+
value = child.content.to_i if child
|
41
|
+
end
|
42
|
+
block ? block.call(value) : value
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def add(dest, value)
|
48
|
+
if cdata
|
49
|
+
dest.child_add(LibXML::XML::Node.new_cdata(value.to_utf))
|
50
|
+
else
|
51
|
+
dest.content = value.to_utf
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
ROXML::TypeRegistry.register(:twodigit, ONIX::TwoDigitType)
|
data/lib/onix/website.rb
ADDED
data/lib/onix/writer.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
module ONIX
|
2
|
+
# The primary way to write a new ONIX file.
|
3
|
+
#
|
4
|
+
# Heres a quick example. The generated file will be nice and boring, as the
|
5
|
+
# header and product objects have no data in them, but you get the idea.
|
6
|
+
#
|
7
|
+
# File.open("output.xml","w") do |output|
|
8
|
+
# header = ONIX::Header.new
|
9
|
+
# ONIX::Writer.open(output, header) do |writer|
|
10
|
+
# writer << ONIX::Product.new
|
11
|
+
# writer << ONIX::Product.new
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# If you prefer, you can build your products using the APAProduct shim layer.
|
16
|
+
#
|
17
|
+
# File.open("output.xml","w") do |output|
|
18
|
+
# header = ONIX::Header.new
|
19
|
+
# ONIX::Writer.open(output, header) do |writer|
|
20
|
+
# writer << ONIX::APAProduct.new
|
21
|
+
# writer << ONIX::APAProduct.new
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
class Writer
|
26
|
+
|
27
|
+
DOCTYPE = "http://www.editeur.org/onix/2.1/03/reference/onix-international.dtd"
|
28
|
+
|
29
|
+
# Default constructor.
|
30
|
+
def initialize(output, header)
|
31
|
+
raise ArgumentError, 'msg must be an ONIX::Header object' unless header.kind_of?(ONIX::Header)
|
32
|
+
@output = output
|
33
|
+
@header = header
|
34
|
+
@finished = false
|
35
|
+
|
36
|
+
start_document
|
37
|
+
end
|
38
|
+
|
39
|
+
# deprecated
|
40
|
+
def start_document
|
41
|
+
puts "ONIX::StreamWriter#start_document is no longer required"
|
42
|
+
end
|
43
|
+
|
44
|
+
def << (product)
|
45
|
+
unless product.kind_of?(ONIX::Product) || product.kind_of?(ONIX::SimpleProduct)
|
46
|
+
raise ArgumentError, 'product must be an ONIX::Product or ONIX::SimpleProduct'
|
47
|
+
end
|
48
|
+
raise "Can't add products to a finished writer" if finished?
|
49
|
+
|
50
|
+
@output.write(product.to_xml.to_s)
|
51
|
+
@output.write("\n")
|
52
|
+
end
|
53
|
+
|
54
|
+
def end_document
|
55
|
+
@output.write("</ONIXMessage>\n")
|
56
|
+
@finished = true
|
57
|
+
end
|
58
|
+
|
59
|
+
def finished?
|
60
|
+
@finished
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.open(output, header)
|
64
|
+
if block_given?
|
65
|
+
writer = self.new(output, header)
|
66
|
+
yield writer
|
67
|
+
writer.end_document
|
68
|
+
else
|
69
|
+
self.new(output, header)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def start_document
|
76
|
+
decl = REXML::XMLDecl.new
|
77
|
+
doctype = REXML::DocType.new('ONIXMessage', "SYSTEM \"#{DOCTYPE}\"")
|
78
|
+
decl.encoding = "utf-8"
|
79
|
+
@output.write(decl.to_s+"\n")
|
80
|
+
@output.write(doctype.to_s+"\n")
|
81
|
+
@output.write("<ONIXMessage>\n")
|
82
|
+
@output.write(@header.to_xml.to_s)
|
83
|
+
@output.write("\n")
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
data/spec/header_spec.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require 'onix'
|
6
|
+
|
7
|
+
context "ONIX::Header" do
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
data_path = File.join(File.dirname(__FILE__),"..","data")
|
11
|
+
file1 = File.join(data_path, "header.xml")
|
12
|
+
@doc = LibXML::XML::Document.file(file1)
|
13
|
+
@header_node = @doc.root
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "should correctly convert to a string" do
|
17
|
+
header = ONIX::Header.parse(@header_node.to_s)
|
18
|
+
header.to_xml.to_s[0,8].should eql("<Header>")
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "should provide read access to first level attibutes" do
|
22
|
+
header = ONIX::Header.parse(@header_node.to_s)
|
23
|
+
|
24
|
+
header.from_ean_number.should eql("1111111111111")
|
25
|
+
header.from_san.should eql("1111111")
|
26
|
+
header.from_company.should eql("Text Company")
|
27
|
+
header.from_email.should eql("james@rainbowbooks.com.au")
|
28
|
+
header.from_person.should eql("James")
|
29
|
+
|
30
|
+
header.to_ean_number.should eql("2222222222222")
|
31
|
+
header.to_san.should eql("2222222")
|
32
|
+
header.to_company.should eql("Company 2")
|
33
|
+
header.to_person.should eql("Chris")
|
34
|
+
|
35
|
+
header.message_note.should eql("A Message")
|
36
|
+
header.message_repeat.should eql(1)
|
37
|
+
header.sent_date.should eql(Date.civil(2008,5,19))
|
38
|
+
|
39
|
+
header.default_language_of_text.should eql("aaa")
|
40
|
+
header.default_price_type_code.should eql(1)
|
41
|
+
header.default_currency_code.should eql("ccc")
|
42
|
+
header.default_linear_unit.should eql("dd")
|
43
|
+
header.default_weight_unit.should eql("ee")
|
44
|
+
header.default_class_of_trade.should eql("f")
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should provide write access to first level attibutes" do
|
48
|
+
header = ONIX::Header.new
|
49
|
+
|
50
|
+
header.from_ean_number = "1111111111111"
|
51
|
+
header.from_ean_number.should eql("1111111111111")
|
52
|
+
|
53
|
+
header.from_san = "1111111"
|
54
|
+
header.from_san.should eql("1111111")
|
55
|
+
|
56
|
+
header.from_company = "Text Company"
|
57
|
+
header.from_company.should eql("Text Company")
|
58
|
+
|
59
|
+
header.from_email = "james@rainbowbooks.com.au"
|
60
|
+
header.from_email.should eql("james@rainbowbooks.com.au")
|
61
|
+
|
62
|
+
header.from_person = "James"
|
63
|
+
header.from_person.should eql("James")
|
64
|
+
|
65
|
+
header.to_ean_number = "2222222222222"
|
66
|
+
header.to_ean_number.should eql("2222222222222")
|
67
|
+
|
68
|
+
header.to_san = "2222222"
|
69
|
+
header.to_san.should eql("2222222")
|
70
|
+
|
71
|
+
header.to_company = "Company 2"
|
72
|
+
header.to_company.should eql("Company 2")
|
73
|
+
|
74
|
+
header.to_person = "Chris"
|
75
|
+
header.to_person.should eql("Chris")
|
76
|
+
|
77
|
+
header.message_note = "A Message"
|
78
|
+
header.message_note.should eql("A Message")
|
79
|
+
|
80
|
+
header.message_repeat = 1
|
81
|
+
header.message_repeat.should eql(1)
|
82
|
+
|
83
|
+
header.sent_date = Date.civil(2008,5,19)
|
84
|
+
header.sent_date.should eql(Date.civil(2008,5,19))
|
85
|
+
|
86
|
+
header.default_language_of_text = "aaa"
|
87
|
+
header.default_language_of_text.should eql("aaa")
|
88
|
+
|
89
|
+
header.default_price_type_code = 1
|
90
|
+
header.default_price_type_code.should eql(1)
|
91
|
+
|
92
|
+
header.default_currency_code = "ccc"
|
93
|
+
header.default_currency_code.should eql("ccc")
|
94
|
+
|
95
|
+
header.default_class_of_trade = "f"
|
96
|
+
header.default_class_of_trade.should eql("f")
|
97
|
+
end
|
98
|
+
|
99
|
+
specify "should correctly handle text with & < and >" do
|
100
|
+
header = ONIX::Header.new
|
101
|
+
|
102
|
+
header.from_company = "James & Healy"
|
103
|
+
header.to_xml.to_s.include?("James & Healy").should be_true
|
104
|
+
|
105
|
+
header.from_company = "James < Healy"
|
106
|
+
header.to_xml.to_s.include?("James < Healy").should be_true
|
107
|
+
|
108
|
+
header.from_company = "James > Healy"
|
109
|
+
header.to_xml.to_s.include?("James > Healy").should be_true
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require 'onix'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
context "ONIX::Product" do
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
data_path = File.join(File.dirname(__FILE__),"..","data")
|
12
|
+
file1 = File.join(data_path, "product.xml")
|
13
|
+
@doc = LibXML::XML::Document.file(file1)
|
14
|
+
@product_node = @doc.root
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should provide read access to first level attibutes" do
|
18
|
+
product = ONIX::Product.parse(@product_node.to_s)
|
19
|
+
|
20
|
+
product.record_reference.should eql("365-9780194351898")
|
21
|
+
product.notification_type.should eql(3)
|
22
|
+
product.product_form.should eql("BC")
|
23
|
+
product.edition_number.should eql(1)
|
24
|
+
product.number_of_pages.should eql(100)
|
25
|
+
product.bic_main_subject.should eql("EB")
|
26
|
+
product.publishing_status.should eql(4)
|
27
|
+
product.publication_date.should eql(Date.civil(1998,9,1))
|
28
|
+
product.year_first_published.should eql(1998)
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "should provide read access to product IDs" do
|
32
|
+
product = ONIX::Product.parse(@product_node.to_s)
|
33
|
+
product.product_identifiers.size.should eql(3)
|
34
|
+
end
|
35
|
+
|
36
|
+
specify "should provide read access to titles" do
|
37
|
+
product = ONIX::Product.parse(@product_node.to_s)
|
38
|
+
product.titles.size.should eql(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should provide read access to subjects" do
|
42
|
+
product = ONIX::Product.parse(@product_node.to_s)
|
43
|
+
product.subjects.size.should eql(1)
|
44
|
+
end
|
45
|
+
|
46
|
+
specify "should provide write access to first level attibutes" do
|
47
|
+
product = ONIX::Product.new
|
48
|
+
|
49
|
+
product.notification_type = 3
|
50
|
+
product.notification_type.should eql(3)
|
51
|
+
product.record_reference = "365-9780194351898"
|
52
|
+
product.record_reference.should eql("365-9780194351898")
|
53
|
+
|
54
|
+
product.product_form = "BC"
|
55
|
+
product.product_form.should eql("BC")
|
56
|
+
|
57
|
+
product.edition_number = 1
|
58
|
+
product.edition_number.should eql(1)
|
59
|
+
|
60
|
+
product.number_of_pages = 100
|
61
|
+
product.number_of_pages.should eql(100)
|
62
|
+
|
63
|
+
product.bic_main_subject = "EB"
|
64
|
+
product.bic_main_subject.should eql("EB")
|
65
|
+
|
66
|
+
product.publishing_status = 4
|
67
|
+
product.publishing_status.should eql(4)
|
68
|
+
|
69
|
+
product.publication_date = Date.civil(1998,9,1)
|
70
|
+
product.publication_date.should eql(Date.civil(1998,9,1))
|
71
|
+
|
72
|
+
product.year_first_published = 1998
|
73
|
+
product.year_first_published.should eql(1998)
|
74
|
+
end
|
75
|
+
end
|