class Xlsxrb::Ooxml::WorkbookWriter
Orchestrates writing a complete XLSX workbook. Generates all required OpenXML parts and assembles them into a ZIP.
Constants
- CT_NS
- DOC_REL
- REL_NS
- SSML_NS
Public Class Methods
(sheets: untyped, ?shared_strings: untyped, ?shared_strings_index: untyped, ?styles: untyped, ?defined_names: untyped, ?core_properties: untyped, ?app_properties: untyped, ?custom_properties: untyped, ?workbook_protection: untyped, ?workbook_properties: untyped) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 45 def initialize(sheets:, shared_strings: [], shared_strings_index: nil, styles: nil, defined_names: nil, core_properties: nil, app_properties: nil, custom_properties: nil, workbook_protection: nil, workbook_properties: nil) @sheets = sheets @shared_strings = shared_strings @shared_strings_index = shared_strings_index @styles = styles || {} @defined_names = defined_names || [] @core_properties = core_properties || {} @app_properties = app_properties || {} @custom_properties = custom_properties || [] @workbook_protection = workbook_protection @workbook_properties = workbook_properties || { update_links: "never" } @drawing_count = 0 @chart_count = 0 @comment_count = 0 @table_count = 0 @pivot_cache_count = 0 @pivot_table_count = 0 end
(untyped target, sheets: untyped, ?shared_strings: untyped, ?shared_strings_index: untyped, ?styles: untyped, ?defined_names: untyped, ?core_properties: untyped, ?app_properties: untyped, ?custom_properties: untyped, ?workbook_protection: untyped, ?workbook_properties: untyped) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 33 def self.write(target, sheets:, shared_strings: [], shared_strings_index: nil, styles: nil, defined_names: nil, core_properties: nil, app_properties: nil, custom_properties: nil, workbook_protection: nil, workbook_properties: nil) Xlsxrb.in_span("Ooxml::WorkbookWriter.write") do writer = new(sheets: sheets, shared_strings: shared_strings, shared_strings_index: shared_strings_index, styles: styles, defined_names: defined_names, core_properties: core_properties, app_properties: app_properties, custom_properties: custom_properties, workbook_protection: workbook_protection, workbook_properties: workbook_properties) writer.write_to(target) end end
Public Instance Methods
(untyped sheet, untyped _idx) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 110 def prepare_sheet_auxiliary(sheet, _idx) sheet_images = sheet[:images] || [] sheet_charts = sheet[:charts] || [] sheet_shapes = sheet[:shapes] || [] sheet_comments = sheet[:comments] || [] sheet_tables = sheet[:tables] || [] sheet_hyperlinks = sheet[:hyperlinks] || [] has_drawing = sheet_images.any? || sheet_charts.any? || sheet_shapes.any? has_comments = sheet_comments.any? sheet_rels = [] drawing_rid = nil vml_rid = nil table_start_rid = nil hyperlink_rels = [] if has_drawing @drawing_count += 1 drawing_rid_num = sheet_rels.size + 1 sheet_rels << { id: "rId#{drawing_rid_num}", type: "#{DOC_REL}/drawing", target: "../drawings/drawing#{@drawing_count}.xml" } drawing_rid = "rId#{drawing_rid_num}" end if has_comments @comment_count += 1 comment_rid_num = sheet_rels.size + 1 sheet_rels << { id: "rId#{comment_rid_num}", type: "#{DOC_REL}/comments", target: "../comments#{@comment_count}.xml" } vml_rid_num = sheet_rels.size + 1 sheet_rels << { id: "rId#{vml_rid_num}", type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing", target: "../drawings/vmlDrawing#{@comment_count}.vml" } vml_rid = "rId#{vml_rid_num}" end sheet_hyperlinks.each do |link| next unless link[:url] h_rid_num = sheet_rels.size + 1 sheet_rels << { id: "rId#{h_rid_num}", type: "#{DOC_REL}/hyperlink", target: link[:url], target_mode: "External" } hyperlink_rels << h_rid_num end h_rid_idx = 0 enriched_hyperlinks = sheet_hyperlinks.map do |link| if link[:url] rid = hyperlink_rels[h_rid_idx] h_rid_idx += 1 link.merge(_rid: rid) else link end end unless sheet_tables.empty? table_start_rid = sheet_rels.size + 1 sheet_tables.each do @table_count += 1 t_rid_num = sheet_rels.size + 1 sheet_rels << { id: "rId#{t_rid_num}", type: "#{DOC_REL}/table", target: "../tables/table#{@table_count}.xml" } end end sheet_pivot_tables = sheet[:pivot_tables] || [] unless sheet_pivot_tables.empty? sheet_pivot_tables.each do @pivot_cache_count += 1 @pivot_table_count += 1 pt_rid_num = sheet_rels.size + 1 sheet_rels << { id: "rId#{pt_rid_num}", type: "#{DOC_REL}/pivotTable", target: "../pivotTables/pivotTable#{@pivot_table_count}.xml" } end end sheet[:_prepared_rels] = sheet_rels sheet[:_enriched_hyperlinks] = enriched_hyperlinks { drawing_rid: drawing_rid, vml_rid: vml_rid, table_start_rid: table_start_rid, enriched_hyperlinks: enriched_hyperlinks, sheet_rels: sheet_rels } end
(untyped zip) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 192 def write_auxiliary_parts(zip) drawing_idx = 0 comment_idx = 0 table_idx = 0 pivot_cache_idx = 0 pivot_table_idx = 0 @sheets.each_with_index do |sheet, idx| sheet_images = sheet[:images] || [] sheet_charts = sheet[:charts] || [] sheet_shapes = sheet[:shapes] || [] sheet_comments = sheet[:comments] || [] sheet_tables = sheet[:tables] || [] has_drawing = sheet_images.any? || sheet_charts.any? || sheet_shapes.any? has_comments = sheet_comments.any? sheet_rels = sheet[:_prepared_rels] || [] if has_drawing drawing_idx += 1 drawing_rels_data = [] drawing_parts = [] chart_writer = Xlsxrb::Ooxml::Writer.new chart_writer.add_sheet(sheet[:name]) unless sheet[:name] == "Sheet1" (sheet[:rows] || []).each do |row| cells = row.is_a?(Hash) ? row[:cells] : row.cells (cells || []).each do |cell| ref = cell.is_a?(Hash) ? cell[:ref] : cell.ref value = cell.is_a?(Hash) ? cell[:value] : cell.value chart_writer.set_cell(ref, value, sheet: sheet[:name]) end end sheet[:cells]&.each do |ref, value| chart_writer.set_cell(ref, value, sheet: sheet[:name]) end sheet_images.each do |img| media_path = "xl/media/image#{drawing_idx}.#{img[:ext] || "png"}" zip.add_binary_entry(media_path, img[:file_data]) drawing_rels_data << { type: :image, target: "../media/image#{drawing_idx}.#{img[:ext] || "png"}" } drawing_parts << { kind: :pic, img: img, rid_index: drawing_rels_data.size } end sheet_charts.each do |chart_options| chart_writer.add_chart(**chart_options) end processed_charts = chart_writer.charts processed_charts.each do |chart| chart_path = "xl/charts/chart#{drawing_rels_data.size + 1}.xml" # simplified zip.add_entry(chart_path, chart_writer.send(:generate_chart_xml, chart)) drawing_rels_data << { type: :chart, target: "../charts/chart#{drawing_rels_data.size + 1}.xml" } drawing_parts << { kind: :chart, chart: chart, rid_index: drawing_rels_data.size } end sheet_shapes.each_with_index do |shape, si| drawing_parts << { kind: :sp, shape: shape, id: drawing_parts.size + si + 2 } end drawing_xml = chart_writer.send(:generate_drawing_xml, drawing_parts) zip.add_entry("xl/drawings/drawing#{drawing_idx}.xml", drawing_xml) unless drawing_rels_data.empty? drawing_rels_xml = chart_writer.send(:generate_drawing_rels, drawing_rels_data) zip.add_entry("xl/drawings/_rels/drawing#{drawing_idx}.xml.rels", drawing_rels_xml) end end if has_comments comment_idx += 1 comment_writer = Xlsxrb::Ooxml::Writer.new sheet_comments.each do |c| comment_writer.add_comment(c[:cell], c[:text], author: c[:author] || "Author") end zip.add_entry("xl/comments#{comment_idx}.xml", comment_writer.send(:generate_comments_xml, comment_writer.comments)) zip.add_entry("xl/drawings/vmlDrawing#{comment_idx}.vml", comment_writer.send(:generate_vml_drawing_xml, comment_writer.comments)) end sheet_tables.each do |tbl| table_idx += 1 zip.add_entry("xl/tables/table#{table_idx}.xml", build_table_xml(tbl, table_idx)) end sheet_pivot_tables = sheet[:pivot_tables] || [] unless sheet_pivot_tables.empty? pivot_writer = Xlsxrb::Ooxml::Writer.new pivot_writer.add_sheet(sheet[:name]) sheet_pivot_tables.each do |pt| pivot_writer.add_pivot_table( pt[:source_ref], row_fields: pt[:row_fields], data_fields: pt[:data_fields], col_fields: pt[:col_fields] || [], dest_ref: pt[:dest_ref] || "E1", name: pt[:name], field_names: pt[:field_names], items: pt[:items], sheet: sheet[:name] ) end pivot_data = pivot_writer.pivot_tables(sheet: sheet[:name]) pivot_data.each do |pt_data| pivot_cache_idx += 1 pivot_table_idx += 1 zip.add_entry("xl/pivotCache/pivotCacheDefinition#{pivot_cache_idx}.xml", pivot_writer.send(:generate_pivot_cache_definition_xml, pt_data, pivot_cache_idx)) zip.add_entry("xl/pivotCache/pivotCacheRecords#{pivot_cache_idx}.xml", pivot_writer.send(:generate_pivot_cache_records_xml, pt_data)) zip.add_entry("xl/pivotTables/pivotTable#{pivot_table_idx}.xml", pivot_writer.send(:generate_pivot_table_xml, pt_data, pivot_cache_idx)) zip.add_entry("xl/pivotCache/_rels/pivotCacheDefinition#{pivot_cache_idx}.xml.rels", pivot_writer.send(:generate_pivot_cache_rels, pivot_cache_idx)) zip.add_entry("xl/pivotTables/_rels/pivotTable#{pivot_table_idx}.xml.rels", pivot_writer.send(:generate_pivot_table_rels, pivot_cache_idx)) end end zip.add_entry("xl/worksheets/_rels/sheet#{idx + 1}.xml.rels", build_sheet_rels_from_list(sheet_rels)) unless sheet_rels.empty? end end
(untyped zip) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 314 def write_package_metadata(zip) zip.add_entry("[Content_Types].xml", build_content_types) zip.add_entry("_rels/.rels", build_root_rels) zip.add_entry("xl/workbook.xml", build_workbook_xml) zip.add_entry("xl/_rels/workbook.xml.rels", build_workbook_rels) zip.add_entry("xl/styles.xml", build_styles_xml) write_shared_strings_xml(zip) unless @shared_strings.empty? # Document properties zip.add_entry("docProps/core.xml", build_core_properties_xml) unless @core_properties.empty? zip.add_entry("docProps/app.xml", build_app_properties_xml) unless @app_properties.empty? zip.add_entry("docProps/custom.xml", build_custom_properties_xml) unless @custom_properties.empty? end
(untyped zip) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 328 def write_package_parts(zip) preprocess_conditional_formats! write_auxiliary_parts(zip) write_package_metadata(zip) end
(untyped target) → untyped
Source
# File lib/xlsxrb/ooxml/workbook_writer.rb, line 66 def write_to(target) preprocess_conditional_formats! ZipWriter.open(target) do |zip| @sheets.each_with_index do |sheet, idx| info = prepare_sheet_auxiliary(sheet, idx) sheet_tables = sheet[:tables] || [] zip.start_entry("xl/worksheets/sheet#{idx + 1}.xml") write_worksheet_xml( ZipEntryIO.new(zip), sheet, drawing_rid: info[:drawing_rid], sheet_protection: sheet[:sheet_protection], auto_filter: sheet[:auto_filter], filter_columns: sheet[:filter_columns], sort_state: sheet[:sort_state], merge_cells: sheet[:merge_cells], conditional_formats: sheet[:conditional_formats], data_validations: sheet[:data_validations], hyperlinks: info[:enriched_hyperlinks].empty? ? nil : info[:enriched_hyperlinks], print_options: sheet[:print_options], page_margins: sheet[:page_margins], page_setup: sheet[:page_setup], header_footer: sheet[:header_footer], row_breaks: sheet[:row_breaks], col_breaks: sheet[:col_breaks], freeze_pane: sheet[:freeze_pane], split_pane: sheet[:split_pane], selection: sheet[:selection], sheet_view: sheet[:sheet_view], sheet_properties: sheet[:sheet_properties], tables: sheet_tables, table_start_rid: info[:table_start_rid], legacy_drawing_rid: info[:vml_rid], sparkline_groups: sheet[:sparkline_groups] ) zip.finish_entry end write_package_parts(zip) end end