class Xlsxrb::Ooxml::Reader
Reads cells from an XLSX file.
Constants
- STRICT_SSML_NS
- TRANSITIONAL_SSML_NS
Public Class Methods
Source
# File lib/xlsxrb/ooxml/reader.rb, line 11 def initialize(filepath) @filepath = filepath end
Public Instance Methods
Source
# File lib/xlsxrb/ooxml/reader.rb, line 502 def app_properties # Try standard path first, then discover via rels xml = extract_zip_entry("docProps/app.xml") if xml.nil? || xml.empty? rels_xml = extract_zip_entry("_rels/.rels") return {} if rels_xml.nil? || rels_xml.empty? rels = parse_rels_with_types(rels_xml) app_rel = rels.find { |r| r[:type]&.end_with?("/extended-properties") } return {} unless app_rel target = app_rel[:target] entry_path = target.start_with?("/") ? target.delete_prefix("/") : target xml = extract_zip_entry(entry_path) end return {} if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = AppPropertiesListener.new parser.listen(listener) parser.parse listener.properties end
Returns app properties as a hash.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 273 def auto_filter(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_auto_filter(worksheet_xml) end
Returns the autoFilter range string (e.g. βA1:B10β) or nil.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 209 def borders styles = load_styles return [] if styles.empty? styles[:borders] || [] end
Returns array of border entries from the styles.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 591 def calc_chain xml = extract_zip_entry("xl/calcChain.xml") return [] if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = CalcChainListener.new parser.listen(listener) parser.parse listener.entries end
Returns the calc chain as an array of { ref:, sheet_id: } hashes, or empty array.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 581 def calc_properties parse_workbook_metadata[:calc_properties] end
Returns calc properties (e.g. { calc_id: 191029 }).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 125 def cell_formats(sheet: nil) # Load styles. styles = load_styles return {} if styles.empty? # Parse worksheet to get cell style indices. worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parser = REXML::Parsers::SAX2Parser.new(worksheet_xml) listener = CellStyleListener.new parser.listen(listener) parser.parse result = {} listener.cell_style_indices.each do |cell_ref, xf_index| xf = resolve_effective_xf(styles[:cell_xfs][xf_index], styles[:cell_style_xfs]) next unless xf fmt_id = xf[:num_fmt_id] next unless fmt_id && fmt_id != 0 format_code = resolve_num_fmt_code(fmt_id, styles[:num_fmts]) result[cell_ref] = format_code if format_code end result end
Returns cell format codes as { βA1β => β0.00β } for cells with custom numFmt.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 57 def cell_phonetic(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_cell_phonetic(worksheet_xml) end
Returns cell addresses marked as phonetic: { βA1β => true }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 249 def cell_style_xfs styles = load_styles return [] if styles.empty? styles[:cell_style_xfs] || [] end
Returns array of cellStyleXfs entries (base style format definitions).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 154 def cell_styles(sheet: nil) styles = load_styles return {} if styles.empty? worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? indices = parse_cell_style_indices(worksheet_xml) result = {} indices.each do |cell_ref, xf_index| xf = resolve_effective_xf(styles[:cell_xfs][xf_index], styles[:cell_style_xfs]) next unless xf entry = {} entry[:font] = styles[:fonts][xf[:font_id]] if xf[:font_id]&.positive? && styles[:fonts][xf[:font_id]] entry[:fill] = styles[:fills][xf[:fill_id]] if xf[:fill_id]&.positive? && styles[:fills][xf[:fill_id]] entry[:border] = styles[:borders][xf[:border_id]] if xf[:border_id]&.positive? && styles[:borders][xf[:border_id]] if xf[:num_fmt_id]&.positive? code = resolve_num_fmt_code(xf[:num_fmt_id], styles[:num_fmts]) entry[:num_fmt] = code if code end entry[:alignment] = xf[:alignment] if xf[:alignment] entry[:protection] = xf[:protection] if xf[:protection] entry[:quote_prefix] = true if xf[:quote_prefix] entry[:pivot_button] = true if xf[:pivot_button] result[cell_ref] = entry unless entry.empty? end result end
Returns expanded cell style info: { βA1β => { font:, fill:, border:, num_fmt: } }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 360 def cell_watches(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_cell_watches(worksheet_xml) end
Returns cell watches for the given sheet as an array of cell references.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 257 def cell_xfs styles = load_styles return [] if styles.empty? styles[:cell_xfs] || [] end
Returns array of cellXfs entries (cell format definitions).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 17 def cells(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? shared_strings = load_shared_strings raw_cells = parse_worksheet_cells(worksheet_xml, shared_strings) # Resolve date-formatted cells. styles = load_styles return raw_cells if styles.empty? cell_style_map = parse_cell_style_indices(worksheet_xml) resolve_date_cells(raw_cells, cell_style_map, styles) end
Returns cells for the given sheet (by name or 0-based index). Defaults to the first sheet. Numeric cells with date numFmt are converted to Date.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 706 def charts(sheet: nil) drawing_xml = load_drawing_xml(sheet) return [] if drawing_xml.nil? || drawing_xml.empty? sheet_index = resolve_sheet_index(sheet) drawing_rels = load_drawing_rels(sheet_index) parser = REXML::Parsers::SAX2Parser.new(drawing_xml) listener = DrawingChartsListener.new parser.listen(listener) parser.parse listener.charts.each do |chart| target = drawing_rels[chart[:rid]] next unless target chart[:target] = target chart_path = resolve_drawing_relative_path(target, sheet_index) chart_xml = extract_zip_entry(chart_path) next if chart_xml.nil? || chart_xml.empty? cp = REXML::Parsers::SAX2Parser.new(chart_xml) cl = ChartTypeListener.new cp.listen(cl) cp.parse chart[:chart_type] = cl.chart_type chart[:title] = cl.title chart[:title_overlay] = cl.title_overlay unless cl.title_overlay.nil? chart[:title_font] = cl.title_font if cl.title_font chart[:title_fill_color] = cl.title_fill_color if cl.title_fill_color chart[:title_no_fill] = cl.title_no_fill if cl.title_no_fill chart[:title_line_color] = cl.title_line_color if cl.title_line_color chart[:title_line_width] = cl.title_line_width if cl.title_line_width chart[:title_line_dash] = cl.title_line_dash if cl.title_line_dash chart[:series] = cl.series unless cl.series.empty? chart[:legend] = cl.legend unless cl.legend.empty? if cl.legend_font chart[:legend] ||= {} chart[:legend][:font] = cl.legend_font end chart[:data_labels] = cl.data_labels unless cl.data_labels.empty? chart[:cat_axis_title] = cl.cat_axis_title if cl.cat_axis_title chart[:val_axis_title] = cl.val_axis_title if cl.val_axis_title chart[:cat_axis_title_font] = cl.cat_axis_title_font if cl.cat_axis_title_font chart[:val_axis_title_font] = cl.val_axis_title_font if cl.val_axis_title_font chart[:cat_axis_title_fill] = cl.cat_axis_title_fill if cl.cat_axis_title_fill chart[:cat_axis_title_no_fill] = cl.cat_axis_title_no_fill if cl.cat_axis_title_no_fill chart[:cat_axis_title_line_color] = cl.cat_axis_title_line_color if cl.cat_axis_title_line_color chart[:cat_axis_title_line_width] = cl.cat_axis_title_line_width if cl.cat_axis_title_line_width chart[:cat_axis_title_line_dash] = cl.cat_axis_title_line_dash if cl.cat_axis_title_line_dash chart[:val_axis_title_fill] = cl.val_axis_title_fill if cl.val_axis_title_fill chart[:val_axis_title_no_fill] = cl.val_axis_title_no_fill if cl.val_axis_title_no_fill chart[:val_axis_title_line_color] = cl.val_axis_title_line_color if cl.val_axis_title_line_color chart[:val_axis_title_line_width] = cl.val_axis_title_line_width if cl.val_axis_title_line_width chart[:val_axis_title_line_dash] = cl.val_axis_title_line_dash if cl.val_axis_title_line_dash chart[:title_layout] = cl.title_layout if cl.title_layout chart[:cat_axis_title_layout] = cl.cat_axis_title_layout if cl.cat_axis_title_layout chart[:val_axis_title_layout] = cl.val_axis_title_layout if cl.val_axis_title_layout chart[:title_rotation] = cl.title_rotation if cl.title_rotation chart[:cat_axis_title_rotation] = cl.cat_axis_title_rotation if cl.cat_axis_title_rotation chart[:val_axis_title_rotation] = cl.val_axis_title_rotation if cl.val_axis_title_rotation chart[:grouping] = cl.grouping if cl.grouping chart[:bar_dir] = cl.bar_dir if cl.bar_dir chart[:vary_colors] = cl.vary_colors unless cl.vary_colors.nil? chart[:plot_vis_only] = cl.plot_vis_only unless cl.plot_vis_only.nil? chart[:disp_blanks_as] = cl.disp_blanks_as if cl.disp_blanks_as chart[:style] = cl.style if cl.style chart[:auto_title_deleted] = cl.auto_title_deleted unless cl.auto_title_deleted.nil? chart[:rounded_corners] = cl.rounded_corners unless cl.rounded_corners.nil? chart[:cat_axis_tick_lbl_pos] = cl.cat_axis_tick_lbl_pos if cl.cat_axis_tick_lbl_pos chart[:val_axis_tick_lbl_pos] = cl.val_axis_tick_lbl_pos if cl.val_axis_tick_lbl_pos chart[:cat_axis_major_gridlines] = cl.cat_axis_major_gridlines if cl.cat_axis_major_gridlines chart[:val_axis_major_gridlines] = cl.val_axis_major_gridlines if cl.val_axis_major_gridlines chart[:cat_axis_minor_gridlines] = cl.cat_axis_minor_gridlines if cl.cat_axis_minor_gridlines chart[:val_axis_minor_gridlines] = cl.val_axis_minor_gridlines if cl.val_axis_minor_gridlines chart[:show_d_lbls_over_max] = cl.show_d_lbls_over_max unless cl.show_d_lbls_over_max.nil? chart[:cat_axis_delete] = cl.cat_axis_delete unless cl.cat_axis_delete.nil? chart[:val_axis_delete] = cl.val_axis_delete unless cl.val_axis_delete.nil? chart[:cat_axis_orientation] = cl.cat_axis_orientation if cl.cat_axis_orientation chart[:val_axis_orientation] = cl.val_axis_orientation if cl.val_axis_orientation chart[:gap_width] = cl.gap_width if cl.gap_width chart[:overlap] = cl.overlap if cl.overlap chart[:gap_depth] = cl.gap_depth if cl.gap_depth chart[:bar_shape] = cl.bar_shape if cl.bar_shape chart[:bubble_3d] = cl.bubble_3d unless cl.bubble_3d.nil? chart[:bubble_scale] = cl.bubble_scale if cl.bubble_scale chart[:show_neg_bubbles] = cl.show_neg_bubbles unless cl.show_neg_bubbles.nil? chart[:size_represents] = cl.size_represents if cl.size_represents chart[:view_3d] = cl.view_3d if cl.view_3d chart[:cat_axis_num_fmt] = cl.cat_axis_num_fmt if cl.cat_axis_num_fmt chart[:val_axis_num_fmt] = cl.val_axis_num_fmt if cl.val_axis_num_fmt chart[:cat_axis_major_tick_mark] = cl.cat_axis_major_tick_mark if cl.cat_axis_major_tick_mark chart[:cat_axis_minor_tick_mark] = cl.cat_axis_minor_tick_mark if cl.cat_axis_minor_tick_mark chart[:val_axis_major_tick_mark] = cl.val_axis_major_tick_mark if cl.val_axis_major_tick_mark chart[:val_axis_minor_tick_mark] = cl.val_axis_minor_tick_mark if cl.val_axis_minor_tick_mark chart[:cat_axis_crosses] = cl.cat_axis_crosses if cl.cat_axis_crosses chart[:val_axis_crosses] = cl.val_axis_crosses if cl.val_axis_crosses chart[:cat_axis_crosses_at] = cl.cat_axis_crosses_at if cl.cat_axis_crosses_at chart[:val_axis_crosses_at] = cl.val_axis_crosses_at if cl.val_axis_crosses_at chart[:cat_axis_tick_lbl_skip] = cl.cat_axis_tick_lbl_skip if cl.cat_axis_tick_lbl_skip chart[:cat_axis_tick_mark_skip] = cl.cat_axis_tick_mark_skip if cl.cat_axis_tick_mark_skip chart[:cat_axis_lbl_offset] = cl.cat_axis_lbl_offset if cl.cat_axis_lbl_offset chart[:cat_axis_auto] = cl.cat_axis_auto unless cl.cat_axis_auto.nil? chart[:cat_axis_lbl_algn] = cl.cat_axis_lbl_algn if cl.cat_axis_lbl_algn chart[:cat_axis_no_multi_lvl_lbl] = cl.cat_axis_no_multi_lvl_lbl unless cl.cat_axis_no_multi_lvl_lbl.nil? chart[:val_axis_cross_between] = cl.val_axis_cross_between if cl.val_axis_cross_between chart[:val_axis_major_unit] = cl.val_axis_major_unit if cl.val_axis_major_unit chart[:val_axis_minor_unit] = cl.val_axis_minor_unit if cl.val_axis_minor_unit chart[:val_axis_disp_units] = cl.val_axis_disp_units if cl.val_axis_disp_units chart[:cat_axis_scaling_max] = cl.cat_axis_scaling_max if cl.cat_axis_scaling_max chart[:cat_axis_scaling_min] = cl.cat_axis_scaling_min if cl.cat_axis_scaling_min chart[:val_axis_scaling_max] = cl.val_axis_scaling_max if cl.val_axis_scaling_max chart[:val_axis_scaling_min] = cl.val_axis_scaling_min if cl.val_axis_scaling_min chart[:cat_axis_log_base] = cl.cat_axis_log_base if cl.cat_axis_log_base chart[:val_axis_log_base] = cl.val_axis_log_base if cl.val_axis_log_base chart[:first_slice_ang] = cl.first_slice_ang if cl.first_slice_ang chart[:hole_size] = cl.hole_size if cl.hole_size chart[:smooth] = cl.smooth unless cl.smooth.nil? chart[:marker] = cl.marker unless cl.marker.nil? chart[:drop_lines] = cl.drop_lines unless cl.drop_lines.nil? chart[:hi_low_lines] = cl.hi_low_lines unless cl.hi_low_lines.nil? chart[:ser_lines] = cl.ser_lines unless cl.ser_lines.nil? chart[:up_down_bars] = cl.up_down_bars if cl.up_down_bars chart[:scatter_style] = cl.scatter_style if cl.scatter_style chart[:radar_style] = cl.radar_style if cl.radar_style chart[:cat_axis_pos] = cl.cat_axis_pos if cl.cat_axis_pos chart[:val_axis_pos] = cl.val_axis_pos if cl.val_axis_pos chart[:wireframe] = cl.wireframe unless cl.wireframe.nil? chart[:band_fmts] = cl.band_fmts if cl.band_fmts chart[:of_pie_type] = cl.of_pie_type if cl.of_pie_type chart[:split_type] = cl.split_type if cl.split_type chart[:split_pos] = cl.split_pos if cl.split_pos chart[:cust_split] = cl.cust_split if cl.cust_split&.any? chart[:second_pie_size] = cl.second_pie_size if cl.second_pie_size chart[:data_table] = cl.data_table if cl.data_table chart[:plot_area_fill] = cl.plot_area_fill if cl.plot_area_fill chart[:plot_area_line_color] = cl.plot_area_line_color if cl.plot_area_line_color chart[:plot_area_line_width] = cl.plot_area_line_width if cl.plot_area_line_width chart[:plot_area_line_dash] = cl.plot_area_line_dash if cl.plot_area_line_dash chart[:plot_area_no_fill] = cl.plot_area_no_fill if cl.plot_area_no_fill chart[:plot_area_layout] = cl.plot_area_layout if cl.plot_area_layout chart[:cat_axis_label_rotation] = cl.cat_axis_label_rotation if cl.cat_axis_label_rotation chart[:val_axis_label_rotation] = cl.val_axis_label_rotation if cl.val_axis_label_rotation chart[:cat_axis_font] = cl.cat_axis_font if cl.cat_axis_font chart[:val_axis_font] = cl.val_axis_font if cl.val_axis_font chart[:cat_axis_fill] = cl.cat_axis_fill if cl.cat_axis_fill chart[:cat_axis_no_fill] = cl.cat_axis_no_fill if cl.cat_axis_no_fill chart[:val_axis_fill] = cl.val_axis_fill if cl.val_axis_fill chart[:val_axis_no_fill] = cl.val_axis_no_fill if cl.val_axis_no_fill chart[:cat_axis_line_color] = cl.cat_axis_line_color if cl.cat_axis_line_color chart[:cat_axis_line_width] = cl.cat_axis_line_width if cl.cat_axis_line_width chart[:cat_axis_line_dash] = cl.cat_axis_line_dash if cl.cat_axis_line_dash chart[:val_axis_line_color] = cl.val_axis_line_color if cl.val_axis_line_color chart[:val_axis_line_width] = cl.val_axis_line_width if cl.val_axis_line_width chart[:val_axis_line_dash] = cl.val_axis_line_dash if cl.val_axis_line_dash chart[:floor] = cl.floor if cl.floor chart[:side_wall] = cl.side_wall if cl.side_wall chart[:back_wall] = cl.back_wall if cl.back_wall chart[:cat_axis_type] = cl.cat_axis_type if cl.cat_axis_type chart[:cat_axis_base_time_unit] = cl.cat_axis_base_time_unit if cl.cat_axis_base_time_unit chart[:cat_axis_major_time_unit] = cl.cat_axis_major_time_unit if cl.cat_axis_major_time_unit chart[:cat_axis_minor_time_unit] = cl.cat_axis_minor_time_unit if cl.cat_axis_minor_time_unit chart[:cat_axis_major_unit] = cl.cat_axis_major_unit if cl.cat_axis_major_unit chart[:cat_axis_minor_unit] = cl.cat_axis_minor_unit if cl.cat_axis_minor_unit chart[:chart_fill] = cl.chart_fill if cl.chart_fill chart[:chart_no_fill] = cl.chart_no_fill if cl.chart_no_fill chart[:chart_line_color] = cl.chart_line_color if cl.chart_line_color chart[:chart_line_width] = cl.chart_line_width if cl.chart_line_width chart[:chart_line_dash] = cl.chart_line_dash if cl.chart_line_dash chart[:protection] = cl.protection if cl.protection chart[:print_settings] = cl.print_settings if cl.print_settings chart[:chart_font] = cl.chart_font if cl.chart_font end listener.charts end
Returns charts for the given sheet as an array of hashes. Each hash: { name:, rid:, target:, chart_type:, title: }
Source
# File lib/xlsxrb/ooxml/reader.rb, line 472 def col_breaks(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_print_page(worksheet_xml)[:col_breaks] end
Returns column breaks for the given sheet.
# File lib/xlsxrb/ooxml/reader.rb, line 41 def column_attributes(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_column_attributes(worksheet_xml) end
Returns column attributes as { βAβ => { hidden: true, outline_level: 1 } }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 33 def columns(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_columns(worksheet_xml) end
Returns column widths as { βAβ => 20.0, βBβ => 15.5 } for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 897 def comments(sheet: nil) sheet_index = resolve_sheet_index(sheet) comments_path = find_sheet_rel_target(sheet_index, "/comments") return [] unless comments_path xml = extract_zip_entry(comments_path) return [] if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = CommentsListener.new parser.listen(listener) parser.parse listener.comments end
Returns comments for the given sheet as an array of hashes. Each hash: { ref:, author:, text: }
# File lib/xlsxrb/ooxml/reader.rb, line 319 def conditional_formats(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_conditional_formats(worksheet_xml) end
Returns conditional formatting rules for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 556 def conformance parse_workbook_metadata[:conformance] end
Returns the workbook conformance class (βtransitionalβ or βstrictβ), or nil if not set.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 480 def core_properties # Discover core properties path from _rels/.rels rels_xml = extract_zip_entry("_rels/.rels") return {} if rels_xml.nil? || rels_xml.empty? rels = parse_rels_with_types(rels_xml) core_rel = rels.find { |r| r[:type]&.end_with?("/metadata/core-properties") } return {} unless core_rel target = core_rel[:target] entry_path = target.start_with?("/") ? target.delete_prefix("/") : target xml = extract_zip_entry(entry_path) return {} if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = CorePropertiesListener.new parser.listen(listener) parser.parse listener.properties end
Returns core properties as a hash (e.g. { title: ββ¦β, creator: ββ¦β }).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 527 def custom_properties xml = extract_zip_entry("docProps/custom.xml") if xml.nil? || xml.empty? rels_xml = extract_zip_entry("_rels/.rels") return [] if rels_xml.nil? || rels_xml.empty? rels = parse_rels_with_types(rels_xml) custom_rel = rels.find { |r| r[:type]&.end_with?("/custom-properties") } return [] unless custom_rel target = custom_rel[:target] entry_path = target.start_with?("/") ? target.delete_prefix("/") : target xml = extract_zip_entry(entry_path) end return [] if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = CustomPropertiesListener.new parser.listen(listener) parser.parse listener.properties end
Returns custom document properties as an array of { name:, value:, type: }.
# File lib/xlsxrb/ooxml/reader.rb, line 376 def data_consolidate(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_data_consolidate(worksheet_xml) end
Returns data consolidation settings for the given sheet.
# File lib/xlsxrb/ooxml/reader.rb, line 303 def data_validations(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_data_validations(worksheet_xml) end
Returns data validations as an array of hashes.
# File lib/xlsxrb/ooxml/reader.rb, line 311 def data_validations_options(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_data_validations_options(worksheet_xml) end
Returns data validations container options (disablePrompts, xWindow, yWindow).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 603 def defined_names parse_workbook_metadata[:defined_names] end
Returns defined names as an array of hashes.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 392 def dimension(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_dimension(worksheet_xml) end
Returns the dimension ref string (e.g. βA1:B10β) for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 185 def dxfs styles = load_styles return [] if styles.empty? styles[:dxfs] || [] end
Returns array of differential formats (dxfs) from the styles.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 647 def entry_names names = [] File.open(@filepath, "rb") do |file| loop do sig = file.read(4) break if sig.nil? || sig.bytesize < 4 sig_val = sig.unpack1("V") break if [0x02014b50, 0x06054b50].include?(sig_val) break unless sig_val == 0x04034b50 header = file.read(26) break if header.nil? || header.bytesize < 26 _ver, flags, _cm, _mt, _md, _crc, comp_size, _unc, fname_len, extra_len = header.unpack("v v v v v V V V v v") break if flags.anybits?(0x0008) fname = file.read(fname_len) file.read(extra_len) file.read(comp_size) names << fname end end names end
Returns all ZIP entry paths in the file.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 939 def external_links wb_rels_xml = extract_zip_entry("xl/_rels/workbook.xml.rels") return [] if wb_rels_xml.nil? || wb_rels_xml.empty? # Find external link rels. el_targets = [] wb_rels_xml.scan(/<Relationship\s[^>]*>/) do |rel_tag| next unless rel_tag.include?("/externalLink") target = rel_tag[/Target="([^"]+)"/, 1] el_targets << target if target end return [] if el_targets.empty? el_targets.filter_map do |target| path = target.start_with?("/") ? target[1..] : "xl/#{target}" xml = extract_zip_entry(path) next if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = ExternalLinkListener.new parser.listen(listener) parser.parse # Resolve the external book target from rels. rels_path = path.sub(%r{([^/]+)\.xml$}, '_rels/\1.xml.rels') rels_xml = extract_zip_entry(rels_path) ext_target = nil rels_xml&.scan(/<Relationship[^>]+Target="([^"]+)"/) { |t,| ext_target = t } { target: ext_target, sheet_names: listener.sheet_names } end end
Returns external links from the workbook as an array of hashes. Each hash: { target:, sheet_names: [] }
Source
# File lib/xlsxrb/ooxml/reader.rb, line 586 def file_recovery_properties parse_workbook_metadata[:file_recovery_properties] end
Returns file recovery properties hash.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 566 def file_sharing parse_workbook_metadata[:file_sharing] end
Returns file sharing properties (e.g. { read_only_recommended: true, user_name: βJohnβ }).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 561 def file_version parse_workbook_metadata[:file_version] end
Returns file version properties (e.g. { app_name: βxlβ, last_edited: β7β }).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 201 def fills styles = load_styles return [] if styles.empty? styles[:fills] || [] end
Returns array of fill entries from the styles.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 287 def filter_columns(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_filter_columns(worksheet_xml) end
Returns filter columns as { col_id => filter_hash }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 193 def fonts styles = load_styles return [] if styles.empty? styles[:fonts] || [] end
Returns array of font entries from the styles.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 977 def format_variant workbook_xml = extract_zip_entry("xl/workbook.xml") return :transitional if workbook_xml.nil? || workbook_xml.empty? if workbook_xml.include?(STRICT_SSML_NS) :strict else :transitional end end
Returns :strict or :transitional based on the namespace of the workbook XML.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 416 def freeze_pane(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_sheet_view(worksheet_xml)[:pane] end
Returns freeze pane settings for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 73 def hyperlinks(sheet: nil) sheets = discover_sheets raise ArgumentError, "workbook has no sheets" if sheets.empty? target = resolve_sheet_target(sheets, sheet) raise ArgumentError, "sheet not found: #{sheet.inspect}" if target.nil? entry_path = if target.start_with?("/") target.delete_prefix("/") else "xl/#{target}" end worksheet_xml = extract_zip_entry(entry_path) return {} if worksheet_xml.nil? || worksheet_xml.empty? # Parse hyperlink elements from worksheet. links = [] WorksheetParser.each_event(worksheet_xml, part_name: entry_path) do |event| next unless event.type == :hyperlink ref, rid, display, tooltip, location = event.args link = { ref: ref } link[:rid] = rid if rid link[:display] = display if display link[:tooltip] = tooltip if tooltip link[:location] = location if location links << link end # Parse rels to resolve rId -> URL. rels_path = entry_path.sub(%r{([^/]+)$}, '_rels/\1.rels') rels_xml = extract_zip_entry(rels_path) rid_to_url = {} rid_to_url = parse_rels(rels_xml).transform_values { |v| v } if rels_xml && !rels_xml.empty? result = {} links.each do |link| entry = {} if link[:rid] url = rid_to_url[link[:rid]] entry[:url] = url if url end entry[:display] = link[:display] if link[:display] entry[:tooltip] = link[:tooltip] if link[:tooltip] entry[:location] = link[:location] if link[:location] result[link[:ref]] = entry unless entry.empty? end result end
Returns hyperlinks as { βA1β => βexample.comβ }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 368 def ignored_errors(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_ignored_errors(worksheet_xml) end
Returns ignored errors for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 685 def images(sheet: nil) drawing_xml = load_drawing_xml(sheet) return [] if drawing_xml.nil? || drawing_xml.empty? sheet_index = resolve_sheet_index(sheet) drawing_rels = load_drawing_rels(sheet_index) parser = REXML::Parsers::SAX2Parser.new(drawing_xml) listener = DrawingImagesListener.new parser.listen(listener) parser.parse listener.images.each do |img| target = drawing_rels[img[:embed_rid]] img[:target] = target if target end listener.images end
Returns images for the given sheet as an array of hashes. Each hash: { name:, embed_rid:, target:, from_col:, from_row:, to_col:, to_row:, cx:, cy: }
Source
# File lib/xlsxrb/ooxml/reader.rb, line 225 def indexed_colors styles = load_styles return [] if styles.empty? styles[:indexed_colors] || [] end
Returns indexed colors palette (array of ARGB hex strings).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 679 def macros? entry_names.any? { |n| n.include?("vbaProject.bin") } end
Returns true if the file contains VBA macros (vbaProject.bin).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 65 def merged_cells(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_merge_cells(worksheet_xml) end
Returns merged cell ranges as [βA1:B2β, βC3:D4β].
Source
# File lib/xlsxrb/ooxml/reader.rb, line 233 def mru_colors styles = load_styles return [] if styles.empty? styles[:mru_colors] || [] end
Returns MRU (most recently used) colors (array of color hashes).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 265 def named_cell_styles styles = load_styles return [] if styles.empty? styles[:cell_styles] || [] end
Returns array of named cell styles (cellStyle elements).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 217 def num_fmts styles = load_styles return {} if styles.empty? styles[:num_fmts] || {} end
Returns custom number formats as { numFmtId => formatCode }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 440 def page_margins(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_print_page(worksheet_xml)[:page_margins] end
Returns page margins for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 448 def page_setup(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_print_page(worksheet_xml)[:page_setup] end
Returns page setup for the given sheet.
# File lib/xlsxrb/ooxml/reader.rb, line 336 def phonetic_properties(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_phonetic_pr(worksheet_xml) end
Returns phonetic properties for the given sheet, or nil if not present.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 914 def pivot_tables(sheet: nil) sheet_index = resolve_sheet_index(sheet) pivot_paths = find_sheet_rel_targets(sheet_index, "/pivotTable") return [] if pivot_paths.empty? pivot_paths.filter_map do |path| xml = extract_zip_entry(path) next if xml.nil? || xml.empty? parser = REXML::Parsers::SAX2Parser.new(xml) listener = PivotTableListener.new parser.listen(listener) parser.parse pt = listener.pivot_table next unless pt # Resolve pivotCacheDefinition via pivot table rels. cache_info = load_pivot_cache_definition(path) pt[:cache] = cache_info if cache_info pt end end
Returns pivot tables for the given sheet as an array of hashes. Each hash: { name:, ref:, cache_id:, fields:, row_fields:, col_fields:, data_fields:, cache: }
Source
# File lib/xlsxrb/ooxml/reader.rb, line 608 def print_area(sheet: nil) _sheet_name, idx = resolve_sheet_for_defined_name(sheet) dn = defined_names.find { |d| d[:name] == "_xlnm.Print_Area" && d[:local_sheet_id] == idx } return nil unless dn # Strip the sheet prefix (e.g. "'Sheet1'!$A$1:$D$20" β "$A$1:$D$20") dn[:value]&.sub(/\A'[^']*'!/, "") end
Returns the print area for the given sheet, or nil if not set.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 432 def print_options(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_print_page(worksheet_xml)[:print_options] end
Returns print options for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 618 def print_titles(sheet: nil) _sheet_name, idx = resolve_sheet_for_defined_name(sheet) dn = defined_names.find { |d| d[:name] == "_xlnm.Print_Titles" && d[:local_sheet_id] == idx } return nil unless dn dn[:value] end
Returns the print titles for the given sheet, or nil if not set.
# File lib/xlsxrb/ooxml/reader.rb, line 352 def protected_ranges(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_protected_ranges(worksheet_xml) end
Returns protected ranges for the given sheet as an array of hashes.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 674 def raw_entry(name) extract_zip_entry(name) end
Returns raw bytes for a ZIP entry by path.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 49 def row_attributes(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_row_attributes(worksheet_xml) end
Returns row attributes as { 1 => { height: 25.0 }, 3 => { hidden: true } }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 464 def row_breaks(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return [] if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_print_page(worksheet_xml)[:row_breaks] end
Returns row breaks for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 384 def scenarios(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_scenarios(worksheet_xml) end
Returns scenarios for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 424 def selection(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_sheet_view(worksheet_xml)[:selection] end
Returns selection for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 884 def shapes(sheet: nil) drawing_xml = load_drawing_xml(sheet) return [] if drawing_xml.nil? || drawing_xml.empty? parser = REXML::Parsers::SAX2Parser.new(drawing_xml) listener = DrawingShapesListener.new parser.listen(listener) parser.parse listener.shapes end
Returns shapes for the given sheet as an array of hashes. Each hash: { name:, id:, preset:, text:, from_col:, from_row:, to_col:, to_row: }
Source
# File lib/xlsxrb/ooxml/reader.rb, line 400 def sheet_format(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_sheet_format(worksheet_xml) end
Returns sheet format properties (defaultRowHeight, defaultColWidth, baseColWidth).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 642 def sheet_names discover_sheets.map { |s| s[:name] } end
Returns ordered sheet names.
# File lib/xlsxrb/ooxml/reader.rb, line 328 def sheet_properties(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_properties(worksheet_xml) end
Returns sheet-level properties (tabColor, outlinePr) for the given sheet. Returns sheet-level properties (tabColor, outlinePr) for the given sheet.
# File lib/xlsxrb/ooxml/reader.rb, line 344 def sheet_protection(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_sheet_protection(worksheet_xml) end
Returns sheet protection settings as a hash, or nil if unprotected.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 627 def sheet_states sheets = discover_sheets result = {} sheets.each do |s| state = case s[:state] when "hidden" then :hidden when "veryHidden" then :very_hidden else :visible end result[s[:name]] = state end result end
Returns sheet states as { βSheet1β => :visible, βHiddenβ => :hidden }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 408 def sheet_view(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_sheet_view(worksheet_xml)[:view] end
Returns sheet view properties for the given sheet.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 295 def sort_state(sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return nil if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_sort_state(worksheet_xml) end
Returns sort state as { ref: βA1:B10β, sort_conditions: [β¦] } or nil.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 241 def table_styles styles = load_styles return {} if styles.empty? styles[:table_styles] || {} end
Returns table styles configuration hash.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 281 def tables(sheet: nil) sheet_index = resolve_sheet_index(sheet) load_tables(sheet_index) end
Returns tables for the given sheet as an array of { id:, name:, display_name:, ref:, columns: }.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 551 def workbook_properties parse_workbook_metadata[:workbook_properties] end
Returns workbook properties (e.g. { date1904: false, default_theme_version: 166925 }).
Source
# File lib/xlsxrb/ooxml/reader.rb, line 576 def workbook_protection parse_workbook_metadata[:workbook_protection] end
Returns workbook protection settings as a hash, or nil if unprotected.
Source
# File lib/xlsxrb/ooxml/reader.rb, line 571 def workbook_views parse_workbook_metadata[:workbook_views] end
Returns workbook view properties (e.g. { active_tab: 0 }).