Class: Xlsxrb::Ooxml::Reader
- Inherits:
-
Object
- Object
- Xlsxrb::Ooxml::Reader
- Defined in:
- lib/xlsxrb/ooxml/reader.rb
Overview
Reads cells from an XLSX file.
Defined Under Namespace
Classes: AppPropertiesListener, AutoFilterListener, CalcChainListener, CellStyleListener, CellWatchesListener, ChartTypeListener, ColumnsListener, CommentsListener, ConditionalFormattingListener, CorePropertiesListener, CustomPropertiesListener, DataConsolidateListener, DataValidationsListener, DimensionListener, DrawingChartsListener, DrawingImagesListener, DrawingShapesListener, ExternalLinkListener, HyperlinksListener, IgnoredErrorsListener, MergeCellsListener, PhoneticPrListener, PivotCacheDefinitionListener, PivotCacheRecordsListener, PivotTableListener, PrintPageListener, ProtectedRangesListener, RelsListener, ScenariosListener, SharedStringsListener, SheetFormatListener, SheetPropertiesListener, SheetProtectionListener, SheetViewListener, SortStateListener, StylesListener, TableListener, WorkbookListener, WorksheetListener
Constant Summary collapse
- STRICT_SSML_NS =
"http://purl.oclc.org/ooxml/spreadsheetml/main/2006/main"- TRANSITIONAL_SSML_NS =
"http://schemas.openxmlformats.org/spreadsheetml/2006/main"
Instance Method Summary collapse
-
#app_properties ⇒ Object
Returns app properties as a hash.
-
#auto_filter(sheet: nil) ⇒ Object
Returns the autoFilter range string (e.g. "A1:B10") or nil.
-
#borders ⇒ Object
Returns array of border entries from the styles.
-
#calc_chain ⇒ Object
Returns the calc chain as an array of { ref:, sheet_id: } hashes, or empty array.
-
#calc_properties ⇒ Object
Returns calc properties (e.g. { calc_id: 191029 }).
-
#cell_formats(sheet: nil) ⇒ Object
Returns cell format codes as { "A1" => "0.00" } for cells with custom numFmt.
-
#cell_phonetic(sheet: nil) ⇒ Object
Returns cell addresses marked as phonetic: { "A1" => true }.
-
#cell_style_xfs ⇒ Object
Returns array of cellStyleXfs entries (base style format definitions).
-
#cell_styles(sheet: nil) ⇒ Object
Returns expanded cell style info: { "A1" => { font:, fill:, border:, num_fmt: } }.
-
#cell_watches(sheet: nil) ⇒ Object
Returns cell watches for the given sheet as an array of cell references.
-
#cell_xfs ⇒ Object
Returns array of cellXfs entries (cell format definitions).
-
#cells(sheet: nil) ⇒ Object
Returns cells for the given sheet (by name or 0-based index).
-
#charts(sheet: nil) ⇒ Object
Returns charts for the given sheet as an array of hashes.
-
#col_breaks(sheet: nil) ⇒ Object
Returns column breaks for the given sheet.
-
#column_attributes(sheet: nil) ⇒ Object
Returns column attributes as { "A" => { hidden: true, outline_level: 1 } }.
-
#columns(sheet: nil) ⇒ Object
Returns column widths as { "A" => 20.0, "B" => 15.5 } for the given sheet.
-
#comments(sheet: nil) ⇒ Object
Returns comments for the given sheet as an array of hashes.
-
#conditional_formats(sheet: nil) ⇒ Object
Returns conditional formatting rules for the given sheet.
-
#conformance ⇒ Object
Returns the workbook conformance class ("transitional" or "strict"), or nil if not set.
-
#core_properties ⇒ Object
Returns core properties as a hash (e.g. { title: "...", creator: "..." }).
-
#custom_properties ⇒ Object
Returns custom document properties as an array of { name:, value:, type: }.
-
#data_consolidate(sheet: nil) ⇒ Object
Returns data consolidation settings for the given sheet.
-
#data_validations(sheet: nil) ⇒ Object
Returns data validations as an array of hashes.
-
#data_validations_options(sheet: nil) ⇒ Object
Returns data validations container options (disablePrompts, xWindow, yWindow).
-
#defined_names ⇒ Object
Returns defined names as an array of hashes.
-
#dimension(sheet: nil) ⇒ Object
Returns the dimension ref string (e.g. "A1:B10") for the given sheet.
-
#dxfs ⇒ Object
Returns array of differential formats (dxfs) from the styles.
-
#entry_names ⇒ Object
Returns all ZIP entry paths in the file.
-
#external_links ⇒ Object
Returns external links from the workbook as an array of hashes.
-
#file_recovery_properties ⇒ Object
Returns file recovery properties hash.
-
#file_sharing ⇒ Object
Returns file sharing properties (e.g. { read_only_recommended: true, user_name: "John" }).
-
#file_version ⇒ Object
Returns file version properties (e.g. { app_name: "xl", last_edited: "7" }).
-
#fills ⇒ Object
Returns array of fill entries from the styles.
-
#filter_columns(sheet: nil) ⇒ Object
Returns filter columns as { col_id => filter_hash }.
-
#fonts ⇒ Object
Returns array of font entries from the styles.
-
#format_variant ⇒ Object
Returns :strict or :transitional based on the namespace of the workbook XML.
-
#freeze_pane(sheet: nil) ⇒ Object
Returns freeze pane settings for the given sheet.
-
#header_footer(sheet: nil) ⇒ Object
Returns header/footer for the given sheet.
-
#hyperlinks(sheet: nil) ⇒ Object
Returns hyperlinks as { "A1" => "https://example.com" }.
-
#ignored_errors(sheet: nil) ⇒ Object
Returns ignored errors for the given sheet.
-
#images(sheet: nil) ⇒ Object
Returns images for the given sheet as an array of hashes.
-
#indexed_colors ⇒ Object
Returns indexed colors palette (array of ARGB hex strings).
-
#initialize(filepath) ⇒ Reader
constructor
A new instance of Reader.
-
#macros? ⇒ Boolean
Returns true if the file contains VBA macros (vbaProject.bin).
-
#merged_cells(sheet: nil) ⇒ Object
Returns merged cell ranges as ["A1:B2", "C3:D4"].
-
#mru_colors ⇒ Object
Returns MRU (most recently used) colors (array of color hashes).
-
#named_cell_styles ⇒ Object
Returns array of named cell styles (cellStyle elements).
-
#num_fmts ⇒ Object
Returns custom number formats as { numFmtId => formatCode }.
-
#page_margins(sheet: nil) ⇒ Object
Returns page margins for the given sheet.
-
#page_setup(sheet: nil) ⇒ Object
Returns page setup for the given sheet.
-
#phonetic_properties(sheet: nil) ⇒ Object
Returns phonetic properties for the given sheet, or nil if not present.
-
#pivot_tables(sheet: nil) ⇒ Object
Returns pivot tables for the given sheet as an array of hashes.
-
#print_area(sheet: nil) ⇒ Object
Returns the print area for the given sheet, or nil if not set.
-
#print_options(sheet: nil) ⇒ Object
Returns print options for the given sheet.
-
#print_titles(sheet: nil) ⇒ Object
Returns the print titles for the given sheet, or nil if not set.
-
#protected_ranges(sheet: nil) ⇒ Object
Returns protected ranges for the given sheet as an array of hashes.
-
#raw_entry(name) ⇒ Object
Returns raw bytes for a ZIP entry by path.
-
#row_attributes(sheet: nil) ⇒ Object
Returns row attributes as { 1 => { height: 25.0 }, 3 => { hidden: true } }.
-
#row_breaks(sheet: nil) ⇒ Object
Returns row breaks for the given sheet.
-
#scenarios(sheet: nil) ⇒ Object
Returns scenarios for the given sheet.
-
#selection(sheet: nil) ⇒ Object
Returns selection for the given sheet.
-
#shapes(sheet: nil) ⇒ Object
Returns shapes for the given sheet as an array of hashes.
-
#sheet_format(sheet: nil) ⇒ Object
Returns sheet format properties (defaultRowHeight, defaultColWidth, baseColWidth).
-
#sheet_names ⇒ Object
Returns ordered sheet names.
-
#sheet_properties(sheet: nil) ⇒ Object
Returns sheet-level properties (tabColor, outlinePr) for the given sheet.
-
#sheet_protection(sheet: nil) ⇒ Object
Returns sheet protection settings as a hash, or nil if unprotected.
-
#sheet_states ⇒ Object
Returns sheet states as { "Sheet1" => :visible, "Hidden" => :hidden }.
-
#sheet_view(sheet: nil) ⇒ Object
Returns sheet view properties for the given sheet.
-
#sort_state(sheet: nil) ⇒ Object
Returns sort state as { ref: "A1:B10", sort_conditions: [...] } or nil.
-
#table_styles ⇒ Object
Returns table styles configuration hash.
-
#tables(sheet: nil) ⇒ Object
Returns tables for the given sheet as an array of { id:, name:, display_name:, ref:, columns: }.
-
#workbook_properties ⇒ Object
Returns workbook properties (e.g. { date1904: false, default_theme_version: 166925 }).
-
#workbook_protection ⇒ Object
Returns workbook protection settings as a hash, or nil if unprotected.
-
#workbook_views ⇒ Object
Returns workbook view properties (e.g. { active_tab: 0 }).
Constructor Details
#initialize(filepath) ⇒ Reader
Returns a new instance of Reader.
11 12 13 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 11 def initialize(filepath) @filepath = filepath end |
Instance Method Details
#app_properties ⇒ Object
Returns app properties as a hash.
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
# 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 |
#auto_filter(sheet: nil) ⇒ Object
Returns the autoFilter range string (e.g. "A1:B10") or nil.
273 274 275 276 277 278 |
# 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 |
#borders ⇒ Object
Returns array of border entries from the styles.
209 210 211 212 213 214 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 209 def borders styles = load_styles return [] if styles.empty? styles[:borders] || [] end |
#calc_chain ⇒ Object
Returns the calc chain as an array of { ref:, sheet_id: } hashes, or empty array.
591 592 593 594 595 596 597 598 599 600 |
# 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 |
#calc_properties ⇒ Object
Returns calc properties (e.g. { calc_id: 191029 }).
581 582 583 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 581 def calc_properties [:calc_properties] end |
#cell_formats(sheet: nil) ⇒ Object
Returns cell format codes as { "A1" => "0.00" } for cells with custom numFmt.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# 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 |
#cell_phonetic(sheet: nil) ⇒ Object
Returns cell addresses marked as phonetic: { "A1" => true }.
57 58 59 60 61 62 |
# 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 |
#cell_style_xfs ⇒ Object
Returns array of cellStyleXfs entries (base style format definitions).
249 250 251 252 253 254 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 249 def cell_style_xfs styles = load_styles return [] if styles.empty? styles[:cell_style_xfs] || [] end |
#cell_styles(sheet: nil) ⇒ Object
Returns expanded cell style info: { "A1" => { font:, fill:, border:, num_fmt: } }.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# 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 |
#cell_watches(sheet: nil) ⇒ Object
Returns cell watches for the given sheet as an array of cell references.
360 361 362 363 364 365 |
# 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 |
#cell_xfs ⇒ Object
Returns array of cellXfs entries (cell format definitions).
257 258 259 260 261 262 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 257 def cell_xfs styles = load_styles return [] if styles.empty? styles[:cell_xfs] || [] end |
#cells(sheet: nil) ⇒ Object
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.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# 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 |
#charts(sheet: nil) ⇒ Object
Returns charts for the given sheet as an array of hashes. Each hash: { name:, rid:, target:, chart_type:, title: }
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 |
# 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. unless cl..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. if cl. 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. if cl. 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. if cl. 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 |
#col_breaks(sheet: nil) ⇒ Object
Returns column breaks for the given sheet.
472 473 474 475 476 477 |
# 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 |
#column_attributes(sheet: nil) ⇒ Object
Returns column attributes as { "A" => { hidden: true, outline_level: 1 } }.
41 42 43 44 45 46 |
# 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 |
#columns(sheet: nil) ⇒ Object
Returns column widths as { "A" => 20.0, "B" => 15.5 } for the given sheet.
33 34 35 36 37 38 |
# 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 |
#comments(sheet: nil) ⇒ Object
Returns comments for the given sheet as an array of hashes. Each hash: { ref:, author:, text: }
897 898 899 900 901 902 903 904 905 906 907 908 909 910 |
# 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 |
#conditional_formats(sheet: nil) ⇒ Object
Returns conditional formatting rules for the given sheet.
319 320 321 322 323 324 |
# 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 |
#conformance ⇒ Object
Returns the workbook conformance class ("transitional" or "strict"), or nil if not set.
556 557 558 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 556 def conformance [:conformance] end |
#core_properties ⇒ Object
Returns core properties as a hash (e.g. { title: "...", creator: "..." }).
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
# 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 |
#custom_properties ⇒ Object
Returns custom document properties as an array of { name:, value:, type: }.
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 |
# 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 |
#data_consolidate(sheet: nil) ⇒ Object
Returns data consolidation settings for the given sheet.
376 377 378 379 380 381 |
# 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 |
#data_validations(sheet: nil) ⇒ Object
Returns data validations as an array of hashes.
303 304 305 306 307 308 |
# 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 |
#data_validations_options(sheet: nil) ⇒ Object
Returns data validations container options (disablePrompts, xWindow, yWindow).
311 312 313 314 315 316 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 311 def (sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? (worksheet_xml) end |
#defined_names ⇒ Object
Returns defined names as an array of hashes.
603 604 605 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 603 def defined_names [:defined_names] end |
#dimension(sheet: nil) ⇒ Object
Returns the dimension ref string (e.g. "A1:B10") for the given sheet.
392 393 394 395 396 397 |
# 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 |
#dxfs ⇒ Object
Returns array of differential formats (dxfs) from the styles.
185 186 187 188 189 190 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 185 def dxfs styles = load_styles return [] if styles.empty? styles[:dxfs] || [] end |
#entry_names ⇒ Object
Returns all ZIP entry paths in the file.
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
# 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 |
#external_links ⇒ Object
Returns external links from the workbook as an array of hashes. Each hash: { target:, sheet_names: [] }
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
# 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 |
#file_recovery_properties ⇒ Object
Returns file recovery properties hash.
586 587 588 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 586 def file_recovery_properties [:file_recovery_properties] end |
#file_sharing ⇒ Object
Returns file sharing properties (e.g. { read_only_recommended: true, user_name: "John" }).
566 567 568 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 566 def file_sharing [:file_sharing] end |
#file_version ⇒ Object
Returns file version properties (e.g. { app_name: "xl", last_edited: "7" }).
561 562 563 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 561 def file_version [:file_version] end |
#fills ⇒ Object
Returns array of fill entries from the styles.
201 202 203 204 205 206 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 201 def fills styles = load_styles return [] if styles.empty? styles[:fills] || [] end |
#filter_columns(sheet: nil) ⇒ Object
Returns filter columns as { col_id => filter_hash }.
287 288 289 290 291 292 |
# 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 |
#fonts ⇒ Object
Returns array of font entries from the styles.
193 194 195 196 197 198 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 193 def fonts styles = load_styles return [] if styles.empty? styles[:fonts] || [] end |
#format_variant ⇒ Object
Returns :strict or :transitional based on the namespace of the workbook XML.
977 978 979 980 981 982 983 984 985 986 |
# 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 |
#freeze_pane(sheet: nil) ⇒ Object
Returns freeze pane settings for the given sheet.
416 417 418 419 420 421 |
# 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 |
#header_footer(sheet: nil) ⇒ Object
Returns header/footer for the given sheet.
456 457 458 459 460 461 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 456 def (sheet: nil) worksheet_xml = load_worksheet_xml(sheet) return {} if worksheet_xml.nil? || worksheet_xml.empty? parse_worksheet_print_page(worksheet_xml)[:header_footer] end |
#hyperlinks(sheet: nil) ⇒ Object
Returns hyperlinks as { "A1" => "https://example.com" }.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# 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 |
#ignored_errors(sheet: nil) ⇒ Object
Returns ignored errors for the given sheet.
368 369 370 371 372 373 |
# 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 |
#images(sheet: nil) ⇒ Object
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: }
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
# 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 |
#indexed_colors ⇒ Object
Returns indexed colors palette (array of ARGB hex strings).
225 226 227 228 229 230 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 225 def indexed_colors styles = load_styles return [] if styles.empty? styles[:indexed_colors] || [] end |
#macros? ⇒ Boolean
Returns true if the file contains VBA macros (vbaProject.bin).
679 680 681 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 679 def macros? entry_names.any? { |n| n.include?("vbaProject.bin") } end |
#merged_cells(sheet: nil) ⇒ Object
Returns merged cell ranges as ["A1:B2", "C3:D4"].
65 66 67 68 69 70 |
# 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 |
#mru_colors ⇒ Object
Returns MRU (most recently used) colors (array of color hashes).
233 234 235 236 237 238 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 233 def mru_colors styles = load_styles return [] if styles.empty? styles[:mru_colors] || [] end |
#named_cell_styles ⇒ Object
Returns array of named cell styles (cellStyle elements).
265 266 267 268 269 270 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 265 def named_cell_styles styles = load_styles return [] if styles.empty? styles[:cell_styles] || [] end |
#num_fmts ⇒ Object
Returns custom number formats as { numFmtId => formatCode }.
217 218 219 220 221 222 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 217 def num_fmts styles = load_styles return {} if styles.empty? styles[:num_fmts] || {} end |
#page_margins(sheet: nil) ⇒ Object
Returns page margins for the given sheet.
440 441 442 443 444 445 |
# 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 |
#page_setup(sheet: nil) ⇒ Object
Returns page setup for the given sheet.
448 449 450 451 452 453 |
# 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 |
#phonetic_properties(sheet: nil) ⇒ Object
Returns phonetic properties for the given sheet, or nil if not present.
336 337 338 339 340 341 |
# 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 |
#pivot_tables(sheet: nil) ⇒ Object
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: }
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 |
# 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 |
#print_area(sheet: nil) ⇒ Object
Returns the print area for the given sheet, or nil if not set.
608 609 610 611 612 613 614 615 |
# 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 |
#print_options(sheet: nil) ⇒ Object
Returns print options for the given sheet.
432 433 434 435 436 437 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 432 def (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 |
#print_titles(sheet: nil) ⇒ Object
Returns the print titles for the given sheet, or nil if not set.
618 619 620 621 622 623 624 |
# 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 |
#protected_ranges(sheet: nil) ⇒ Object
Returns protected ranges for the given sheet as an array of hashes.
352 353 354 355 356 357 |
# 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 |
#raw_entry(name) ⇒ Object
Returns raw bytes for a ZIP entry by path.
674 675 676 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 674 def raw_entry(name) extract_zip_entry(name) end |
#row_attributes(sheet: nil) ⇒ Object
Returns row attributes as { 1 => { height: 25.0 }, 3 => { hidden: true } }.
49 50 51 52 53 54 |
# 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 |
#row_breaks(sheet: nil) ⇒ Object
Returns row breaks for the given sheet.
464 465 466 467 468 469 |
# 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 |
#scenarios(sheet: nil) ⇒ Object
Returns scenarios for the given sheet.
384 385 386 387 388 389 |
# 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 |
#selection(sheet: nil) ⇒ Object
Returns selection for the given sheet.
424 425 426 427 428 429 |
# 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 |
#shapes(sheet: nil) ⇒ Object
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: }
884 885 886 887 888 889 890 891 892 893 |
# 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 |
#sheet_format(sheet: nil) ⇒ Object
Returns sheet format properties (defaultRowHeight, defaultColWidth, baseColWidth).
400 401 402 403 404 405 |
# 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 |
#sheet_names ⇒ Object
Returns ordered sheet names.
642 643 644 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 642 def sheet_names discover_sheets.map { |s| s[:name] } end |
#sheet_properties(sheet: nil) ⇒ Object
Returns sheet-level properties (tabColor, outlinePr) for the given sheet. Returns sheet-level properties (tabColor, outlinePr) for the given sheet.
328 329 330 331 332 333 |
# 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 |
#sheet_protection(sheet: nil) ⇒ Object
Returns sheet protection settings as a hash, or nil if unprotected.
344 345 346 347 348 349 |
# 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 |
#sheet_states ⇒ Object
Returns sheet states as { "Sheet1" => :visible, "Hidden" => :hidden }.
627 628 629 630 631 632 633 634 635 636 637 638 639 |
# 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 |
#sheet_view(sheet: nil) ⇒ Object
Returns sheet view properties for the given sheet.
408 409 410 411 412 413 |
# 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 |
#sort_state(sheet: nil) ⇒ Object
Returns sort state as { ref: "A1:B10", sort_conditions: [...] } or nil.
295 296 297 298 299 300 |
# 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 |
#table_styles ⇒ Object
Returns table styles configuration hash.
241 242 243 244 245 246 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 241 def table_styles styles = load_styles return {} if styles.empty? styles[:table_styles] || {} end |
#tables(sheet: nil) ⇒ Object
Returns tables for the given sheet as an array of { id:, name:, display_name:, ref:, columns: }.
281 282 283 284 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 281 def tables(sheet: nil) sheet_index = resolve_sheet_index(sheet) load_tables(sheet_index) end |
#workbook_properties ⇒ Object
Returns workbook properties (e.g. { date1904: false, default_theme_version: 166925 }).
551 552 553 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 551 def workbook_properties [:workbook_properties] end |
#workbook_protection ⇒ Object
Returns workbook protection settings as a hash, or nil if unprotected.
576 577 578 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 576 def workbook_protection [:workbook_protection] end |
#workbook_views ⇒ Object
Returns workbook view properties (e.g. { active_tab: 0 }).
571 572 573 |
# File 'lib/xlsxrb/ooxml/reader.rb', line 571 def workbook_views [:workbook_views] end |