lib/rubyXL/objects/relationships.rb in rubyXL-2.5.7 vs lib/rubyXL/objects/relationships.rb in rubyXL-3.0.0
- old
+ new
@@ -5,96 +5,212 @@
class RID < OOXMLObject
define_attribute(:'r:id', :string, :required => true)
end
class Relationship < OOXMLObject
- define_attribute(:Id, :string)
- define_attribute(:Type, :string)
- define_attribute(:Target, :string)
+ define_attribute(:Id, :string)
+ define_attribute(:Type, :string)
+ define_attribute(:Target, :string)
+ define_attribute(:TargetMode, :string)
define_element_name 'Relationship'
end
class OOXMLRelationshipsFile < OOXMLTopLevelObject
define_child_node(RubyXL::Relationship, :collection => true, :accessor => :relationships)
define_element_name 'Relationships'
set_namespaces('http://schemas.openxmlformats.org/package/2006/relationships' => '')
- def document_relationship(target, type)
+ attr_accessor :related_files, :owner
+
+ @@debug = nil # Change to 0 to enable debug output
+
+ def new_relationship(target, type)
RubyXL::Relationship.new(:id => "rId#{relationships.size + 1}",
- :type => "http://schemas.openxmlformats.org/officeDocument/2006/relationships/#{type}",
+ :type => type,
:target => target)
end
- protected :document_relationship
+ protected :new_relationship
- def metadata_relationship(target, type)
- RubyXL::Relationship.new(:id => "rId#{relationships.size + 1}",
- :type => "http://schemas.openxmlformats.org/package/2006/relationships/metadata/#{type}",
- :target => target)
+ def add_relationship(obj)
+ return if obj.nil?
+ relationships << RubyXL::Relationship.new(:id => "rId#{relationships.size + 1}",
+ :type => obj.class::REL_TYPE,
+ :target => obj.xlsx_path)
end
- protected :metadata_relationship
+ protected :add_relationship
+ def self.save_order
+ 0
+ end
+
def find_by_rid(r_id)
relationships.find { |r| r.id == r_id }
end
def find_by_target(target)
relationships.find { |r| r.target == target }
end
- end
+ def self.get_class_by_rel_type(rel_type)
+ unless defined?(@@rel_hash)
+ @@rel_hash = {}
+ RubyXL.constants.each { |c|
+ klass = RubyXL.const_get(c)
+ if klass.is_a?(Class) && klass.const_defined?(:REL_TYPE) then
+ @@rel_hash[klass::REL_TYPE] = klass
+ end
+ }
+ end
+
+ @@rel_hash[rel_type]
+ end
+
+ def load_related_files(zipdir_path, base_file_name = '')
+ self.related_files = {}
+
+ @@debug +=2 if @@debug
+
+ self.relationships.each { |rel|
+ next if rel.target_mode == 'External'
+
+ file_path = Pathname.new(rel.target)
+
+ if !file_path.absolute? then
+ file_path = (Pathname.new(File.dirname(base_file_name)) + file_path).cleanpath
+ end
+
+ klass = RubyXL::OOXMLRelationshipsFile.get_class_by_rel_type(rel.type)
+
+ if klass.nil? then
+ puts "*** WARNING: storage class not found for #{rel.target} (#{rel.type})"
+ klass = GenericStorageObject
+ end
+
+ puts "--> DEBUG:#{' ' * @@debug}Loading #{klass} (#{rel.id}): #{file_path}" if @@debug
+
+ obj = klass.parse_file(zipdir_path, file_path)
+ obj.load_relationships(zipdir_path, file_path) if obj.respond_to?(:load_relationships)
+ self.related_files[rel.id] = obj
+ }
+
+ @@debug -=2 if @@debug
+
+ related_files
+ end
+
+ def self.load_relationship_file(zipdir_path, base_file_path)
+ rel_file_path = Pathname.new(File.join(File.dirname(base_file_path), '_rels', File.basename(base_file_path) + '.rels')).cleanpath
+
+ puts "--> DEBUG: #{' ' * @@debug}Loading .rel file: #{rel_file_path}" if @@debug
+
+ parse_file(zipdir_path, rel_file_path)
+ end
+
+ def xlsx_path
+ file_path = owner.xlsx_path
+ File.join(File.dirname(file_path), '_rels', File.basename(file_path) + '.rels')
+ end
+
+ end
+
class WorkbookRelationships < OOXMLRelationshipsFile
attr_accessor :workbook
def before_write_xml
self.relationships = []
@workbook.worksheets.each_with_index { |sheet, i|
- relationships << document_relationship(sheet.xlsx_path.gsub(/^xl\//, ''), sheet.rel_type)
+ relationships << new_relationship(sheet.xlsx_path.gsub(/\Axl\//, ''), sheet.class::REL_TYPE)
}
- @workbook.external_links.each_key { |k|
- relationships << document_relationship("externalLinks/#{k}", 'externalLink')
- }
+# @workbook.external_links.each_key { |k|
+# relationships << new_relationship("externalLinks/#{k}", 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink')
+# }
- relationships << document_relationship('theme/theme1.xml', 'theme') if @workbook.theme
- relationships << document_relationship('styles.xml', 'styles') if @workbook.stylesheet
+ relationships << new_relationship('theme/theme1.xml', @workbook.theme.class::REL_TYPE) if @workbook.theme
+ relationships << new_relationship('styles.xml', @workbook.stylesheet.class::REL_TYPE) if @workbook.stylesheet
if @workbook.shared_strings_container && !@workbook.shared_strings_container.strings.empty? then
- relationships << document_relationship('sharedStrings.xml', 'sharedStrings')
+ relationships << new_relationship('sharedStrings.xml', @workbook.shared_strings_container.class::REL_TYPE)
end
if @workbook.calculation_chain && !@workbook.calculation_chain.cells.empty? then
- relationships << document_relationship('calcChain.xml', 'calcChain')
+ relationships << new_relationship('calcChain.xml', @workbook.calculation_chain.class::REL_TYPE)
end
true
end
- def self.xlsx_path
- File.join('xl', '_rels', 'workbook.xml.rels')
- end
-
end
class RootRelationships < OOXMLRelationshipsFile
- attr_accessor :workbook
-
def before_write_xml
self.relationships = []
- relationships << document_relationship('xl/workbook.xml', 'officeDocument')
- relationships << metadata_relationship('docProps/thumbnail.jpeg', 'thumbnail') unless @workbook.thumbnail.empty?
- relationships << metadata_relationship('docProps/core.xml', 'core-properties') if @workbook.core_properties
- relationships << document_relationship('docProps/app.xml', 'extended-properties') if @workbook.document_properties
+ add_relationship(owner.workbook)
+ add_relationship(owner.thumbnail)
+ add_relationship(owner.core_properties)
+ add_relationship(owner.document_properties)
true
end
- def self.xlsx_path
+ def xlsx_path
File.join('_rels', '.rels')
end
+ end
+
+ class SheetRelationshipsFile < OOXMLRelationshipsFile
+ # Insert class specific stuff here once we get to implementing it
+ end
+
+ class DrawingRelationshipsFile < OOXMLRelationshipsFile
+ # Insert class specific stuff here once we get to implementing it
+ end
+
+ class ChartRelationshipsFile < OOXMLRelationshipsFile
+ # Insert class specific stuff here once we get to implementing it
+ end
+
+ module RelationshipSupport
+
+ attr_accessor :generic_storage, :relationship_container
+ def related_objects # Override this method
+ []
+ end
+
+ def collect_related_objects
+ res = related_objects.compact # Avoid tainting +related_objects+ array
+
+ res += generic_storage if generic_storage
+
+ if relationship_container then
+ relationship_container.owner = self
+ res << relationship_container
+ end
+
+ res.each { |o| res += o.collect_related_objects if o.respond_to?(:collect_related_objects) }
+
+ res
+ end
+
+ def store_relationship(related_file, unknown = false)
+ self.generic_storage ||= []
+ puts "WARNING: #{self.class} is not aware what to do with #{related_file.class}" if unknown
+ self.generic_storage << related_file
+ end
+
+ def load_relationships(dir_path, base_file_name = '')
+ self.relationship_container = relationship_file_class.load_relationship_file(dir_path, base_file_name)
+ return if relationship_container.nil?
+
+ relationship_container.load_related_files(dir_path, base_file_name).each_pair { |rid, related_file|
+ attach_relationship(rid, related_file) if related_file
+ }
+ end
+
end
end