require 'rexml/document' require 'date' require 'bigdecimal' module SpreadBase # :nodoc: module Codecs # :nodoc: module OpenDocument12Modules # :nodoc: # Module containing the encoding routines of the OpenDocument12 format. # module Encoding # Actually a document can be opened even without the office:body element, but we simplify the code # by assuming that at least this tree is present. # BASE_CONTENT_XML = %Q[\ / / / / : ] # :nodoc: private # Returns the XML root node # def encode_to_document_node(el_document) root_node = REXML::Document.new(BASE_CONTENT_XML) spreadsheet_node = root_node.elements['//office:document-content/office:body/office:spreadsheet'] styles_node = root_node.elements['//office:document-content/office:automatic-styles'] el_document.column_width_styles.each do | style_name, column_width | encode_style(styles_node, style_name, column_width) end el_document.tables.each do | table | encode_table(table, spreadsheet_node) end root_node end # Currently only encodes column width styles # def encode_style(styles_node, style_name, column_width) style_node = styles_node.add_element('style:style', 'style:name' => style_name, 'style:family' => 'table-column') style_node.add_element('style:table-column-properties', 'style:column-width' => column_width) end def encode_table(table, spreadsheet_node) table_node = spreadsheet_node.add_element('table:table') table_node.attributes['table:name'] = table.name table.column_width_styles.each do | style_name | encode_column(table_node, style_name) if style_name end # At least one column element is required # table_node.add_element('table:table-column') if table.column_width_styles.size == 0 table.data(as_cell: true).each do | row | encode_row(row, table_node) end end # Currently only encodes column width styles # def encode_column(table_node, style_name) table_node.add_element('table:table-column', 'table:style-name' => style_name) end def encode_row(row, table_node) row_node = table_node.add_element('table:table-row') row.each do | cell | encode_cell(cell.value, row_node) end end def encode_cell(value, row_node) cell_node = row_node.add_element('table:table-cell') # WATCH OUT!!! DateTime.new.is_a?( Date )!!! # case value when String cell_node.attributes['office:value-type'] = 'string' cell_value_node = cell_node.add_element('text:p') cell_value_node.text = value.encode('UTF-8') when Time, DateTime cell_node.attributes['office:value-type'] = 'date' cell_node.attributes['table:style-name'] = 'datetime' encoded_value = value.strftime('%Y-%m-%dT%H:%M:%S') cell_node.attributes['office:date-value'] = encoded_value when Date cell_node.attributes['office:value-type'] = 'date' cell_node.attributes['table:style-name'] = 'date' encoded_value = value.strftime('%Y-%m-%d') cell_node.attributes['office:date-value'] = encoded_value when BigDecimal cell_node.attributes['office:value-type'] = 'float' cell_node.attributes['office:value'] = value.to_s('F') when Float, Integer cell_node.attributes['office:value-type'] = 'float' cell_node.attributes['office:value'] = value.to_s when true, false cell_node.attributes['office:value-type'] = 'boolean' cell_node.attributes['table:style-name'] = 'boolean' cell_node.attributes['office:boolean-value'] = value.to_s when nil # do nothing else raise "Unrecognized value class: #{ value.class }" end end end end end end