openxml-xlsx 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -4
- data/example +4 -3
- data/lib/openxml-xlsx.rb +1 -0
- data/lib/openxml/xlsx.rb +30 -0
- data/lib/{xlsx → openxml/xlsx}/elements.rb +4 -2
- data/lib/openxml/xlsx/elements/alignment.rb +22 -0
- data/lib/openxml/xlsx/elements/border.rb +28 -0
- data/lib/openxml/xlsx/elements/border_component.rb +21 -0
- data/lib/openxml/xlsx/elements/border_style.rb +22 -0
- data/lib/openxml/xlsx/elements/cell.rb +96 -0
- data/lib/openxml/xlsx/elements/defined_name.rb +13 -0
- data/lib/openxml/xlsx/elements/font.rb +22 -0
- data/lib/openxml/xlsx/elements/implied_number_format.rb +7 -0
- data/lib/openxml/xlsx/elements/indexed_color.rb +13 -0
- data/lib/openxml/xlsx/elements/number_format.rb +47 -0
- data/lib/openxml/xlsx/elements/pattern_fill.rb +20 -0
- data/lib/openxml/xlsx/elements/relationship.rb +20 -0
- data/lib/openxml/xlsx/elements/row.rb +37 -0
- data/lib/openxml/xlsx/elements/style.rb +29 -0
- data/lib/openxml/xlsx/elements/table_column.rb +8 -0
- data/lib/openxml/xlsx/elements/theme_color.rb +13 -0
- data/lib/openxml/xlsx/package.rb +52 -0
- data/lib/{xlsx → openxml/xlsx}/parts.rb +4 -2
- data/lib/openxml/xlsx/parts/shared_strings.rb +28 -0
- data/lib/openxml/xlsx/parts/stylesheet.rb +80 -0
- data/lib/openxml/xlsx/parts/table.rb +36 -0
- data/lib/openxml/xlsx/parts/workbook.rb +71 -0
- data/lib/openxml/xlsx/parts/worksheet.rb +90 -0
- data/lib/openxml/xlsx/version.rb +5 -0
- data/{xlsx.gemspec → openxml-xlsx.gemspec} +5 -5
- metadata +37 -36
- data/lib/xlsx.rb +0 -28
- data/lib/xlsx/elements/alignment.rb +0 -20
- data/lib/xlsx/elements/border.rb +0 -26
- data/lib/xlsx/elements/border_component.rb +0 -19
- data/lib/xlsx/elements/border_style.rb +0 -20
- data/lib/xlsx/elements/cell.rb +0 -94
- data/lib/xlsx/elements/defined_name.rb +0 -11
- data/lib/xlsx/elements/font.rb +0 -20
- data/lib/xlsx/elements/implied_number_format.rb +0 -5
- data/lib/xlsx/elements/indexed_color.rb +0 -11
- data/lib/xlsx/elements/number_format.rb +0 -45
- data/lib/xlsx/elements/pattern_fill.rb +0 -18
- data/lib/xlsx/elements/relationship.rb +0 -18
- data/lib/xlsx/elements/row.rb +0 -35
- data/lib/xlsx/elements/style.rb +0 -27
- data/lib/xlsx/elements/table_column.rb +0 -6
- data/lib/xlsx/elements/theme_color.rb +0 -11
- data/lib/xlsx/package.rb +0 -50
- data/lib/xlsx/parts/shared_strings.rb +0 -26
- data/lib/xlsx/parts/stylesheet.rb +0 -78
- data/lib/xlsx/parts/table.rb +0 -34
- data/lib/xlsx/parts/workbook.rb +0 -66
- data/lib/xlsx/parts/worksheet.rb +0 -88
- data/lib/xlsx/version.rb +0 -3
@@ -0,0 +1,37 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Elements
|
4
|
+
class Row
|
5
|
+
attr_reader :worksheet, :number, :height, :hidden, :cells
|
6
|
+
|
7
|
+
def initialize(worksheet, options={})
|
8
|
+
@worksheet = worksheet
|
9
|
+
@number = options.fetch(:number)
|
10
|
+
@height = options[:height]
|
11
|
+
@hidden = options[:hidden]
|
12
|
+
@cells = []
|
13
|
+
|
14
|
+
Array(options[:cells]).each do |attributes|
|
15
|
+
add_cell attributes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_cell(attributes)
|
20
|
+
cells.push Xlsx::Elements::Cell.new(self, attributes)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_xml(xml)
|
24
|
+
attributes = {"r" => number}
|
25
|
+
attributes.merge!("ht" => height, "customHeight" => 1) if height
|
26
|
+
attributes.merge!("hidden" => 1) if hidden
|
27
|
+
xml.row(attributes) do
|
28
|
+
cells.each do |cell|
|
29
|
+
cell.to_xml(xml)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Elements
|
4
|
+
class Style < Struct.new(:format_id, :font_id, :fill_id, :border_id, :alignment)
|
5
|
+
|
6
|
+
def initialize(format_id=0, font_id=0, fill_id=0, border_id=0, alignment=nil)
|
7
|
+
super format_id || 0, font_id || 0, fill_id || 0, border_id || 0, alignment
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_xml(xml)
|
11
|
+
attributes = {
|
12
|
+
numFmtId: format_id,
|
13
|
+
fontId: font_id,
|
14
|
+
fillId: fill_id,
|
15
|
+
borderId: border_id }
|
16
|
+
attributes.merge!(applyNumberFormat: 1) if format_id > 0
|
17
|
+
attributes.merge!(applyFont: 1) if font_id > 0
|
18
|
+
attributes.merge!(applyFill: 1) if fill_id > 0
|
19
|
+
attributes.merge!(applyBorder: 1) if border_id > 0
|
20
|
+
attributes.merge!(applyAlignment: 1) if alignment
|
21
|
+
xml.xf(attributes) do
|
22
|
+
alignment.to_xml(xml) if alignment
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "openxml/package"
|
2
|
+
|
3
|
+
module OpenXml
|
4
|
+
module Xlsx
|
5
|
+
class Package < OpenXml::Package
|
6
|
+
attr_reader :xl_rels,
|
7
|
+
:shared_strings,
|
8
|
+
:stylesheet,
|
9
|
+
:workbook
|
10
|
+
|
11
|
+
|
12
|
+
content_types do
|
13
|
+
override "/xl/workbook.xml", TYPE_WORKBOOK
|
14
|
+
override "/xl/worksheets/sheet1.xml", TYPE_WORKSHEET
|
15
|
+
override "/xl/sharedStrings.xml", TYPE_SHARED_STRINGS
|
16
|
+
override "/xl/styles.xml", TYPE_STYLES
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
rels.add_relationship REL_DOCUMENT, "xl/workbook.xml"
|
23
|
+
|
24
|
+
@xl_rels = OpenXml::Parts::Rels.new([
|
25
|
+
{ "Type" => REL_SHARED_STRINGS, "Target" => "sharedStrings.xml" },
|
26
|
+
{ "Type" => REL_STYLES, "Target" => "styles.xml" }
|
27
|
+
])
|
28
|
+
@shared_strings = Xlsx::Parts::SharedStrings.new
|
29
|
+
@stylesheet = Xlsx::Parts::Stylesheet.new
|
30
|
+
@workbook = Xlsx::Parts::Workbook.new(self)
|
31
|
+
|
32
|
+
# docProps/app.xml
|
33
|
+
# docProps/core.xml
|
34
|
+
add_part "xl/_rels/workbook.xml.rels", xl_rels
|
35
|
+
# xl/calcChain.xml
|
36
|
+
add_part "xl/sharedStrings.xml", shared_strings
|
37
|
+
add_part "xl/styles.xml", stylesheet
|
38
|
+
# xl/theme/theme1.xml
|
39
|
+
add_part "xl/workbook.xml", workbook
|
40
|
+
end
|
41
|
+
|
42
|
+
def string_ref(string)
|
43
|
+
shared_strings.reference_of(string)
|
44
|
+
end
|
45
|
+
|
46
|
+
def style_ref(style)
|
47
|
+
stylesheet.reference_of(style)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Parts
|
4
|
+
class SharedStrings < OpenXml::Part
|
5
|
+
attr_reader :strings
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@strings = Hash.new { |hash, key| hash[key] = hash.length }
|
9
|
+
end
|
10
|
+
|
11
|
+
def reference_of(string)
|
12
|
+
strings[string]
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
build_standalone_xml do |xml|
|
17
|
+
xml.sst(xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main", uniqueCount: strings.length) do
|
18
|
+
strings.each do |string, i|
|
19
|
+
xml.si { xml.t(string) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Parts
|
4
|
+
class Stylesheet < OpenXml::Part
|
5
|
+
include Xlsx::Elements
|
6
|
+
|
7
|
+
attr_reader :formats, :fonts, :fills, :borders, :styles
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@formats = []
|
11
|
+
@fonts = [Font.new("Calibri", 12)]
|
12
|
+
@fills = [PatternFill.new("none"), PatternFill.new("gray125")]
|
13
|
+
@borders = [Border.new]
|
14
|
+
@styles = [Style.new]
|
15
|
+
end
|
16
|
+
|
17
|
+
def reference_of(options={})
|
18
|
+
case format = options[:format]
|
19
|
+
when NumberFormat
|
20
|
+
options[:format_id] = Xlsx.index!(formats, format) + NUMBER_FORMAT_START_ID
|
21
|
+
when ImpliedNumberFormat
|
22
|
+
options[:format_id] = format.id
|
23
|
+
end
|
24
|
+
options[:font_id] = Xlsx.index!(fonts, options[:font]) if options.key? :font
|
25
|
+
options[:fill_id] = Xlsx.index!(fills, options[:fill]) if options.key? :fill
|
26
|
+
options[:border_id] = Xlsx.index!(borders, options[:border]) if options.key? :border
|
27
|
+
|
28
|
+
style = Style.new(
|
29
|
+
options.fetch(:format_id, 0),
|
30
|
+
options.fetch(:font_id, 0),
|
31
|
+
options.fetch(:fill_id, 0),
|
32
|
+
options.fetch(:border_id, 0),
|
33
|
+
options.fetch(:alignment, nil))
|
34
|
+
|
35
|
+
Xlsx.index!(styles, style)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_xml
|
39
|
+
build_standalone_xml do |xml|
|
40
|
+
xml.styleSheet(xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main", "xmlns:mc" => "http://schemas.openxmlformats.org/markup-compatibility/2006") do
|
41
|
+
xml.numFmts(count: formats.length) do
|
42
|
+
formats.each_with_index do |format, index|
|
43
|
+
format.to_xml(index + NUMBER_FORMAT_START_ID, xml)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
xml.fonts(count: fonts.length) do
|
48
|
+
fonts.each do |font|
|
49
|
+
font.to_xml(xml)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
xml.fills(count: fills.length) do
|
54
|
+
fills.each do |fill|
|
55
|
+
fill.to_xml(xml)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
xml.borders(count: borders.length) do
|
60
|
+
borders.each do |border|
|
61
|
+
border.to_xml(xml)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
xml.cellXfs(count: styles.length) do
|
66
|
+
styles.each do |style|
|
67
|
+
style.to_xml(xml)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
NUMBER_FORMAT_START_ID = 165.freeze
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Parts
|
4
|
+
class Table < OpenXml::Part
|
5
|
+
attr_reader :id, :name, :ref, :columns
|
6
|
+
|
7
|
+
def initialize(id, name, ref, columns)
|
8
|
+
@id = id
|
9
|
+
@name = name
|
10
|
+
@ref = ref
|
11
|
+
@columns = columns
|
12
|
+
end
|
13
|
+
|
14
|
+
def filename
|
15
|
+
"table#{id}.xml"
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_xml
|
19
|
+
build_standalone_xml do |xml|
|
20
|
+
xml.table(xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
21
|
+
id: id, name: name, displayName: name, ref: ref, totalsRowShown: 0) do
|
22
|
+
xml.autoFilter ref: ref
|
23
|
+
xml.tableColumns(count: columns.length) do
|
24
|
+
columns.each_with_index do |column, index|
|
25
|
+
xml.tableColumn(id: index + 1, name: column.name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
xml.tableStyleInfo(name: "TableStyleLight6", showFirstColumn: 0, showLastColumn: 0, showRowStripes: 1, showColumnStripes: 0)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Parts
|
4
|
+
class Workbook < OpenXml::Part
|
5
|
+
attr_reader :package, :worksheets, :tables, :defined_names
|
6
|
+
|
7
|
+
def initialize(package)
|
8
|
+
@package = package
|
9
|
+
@worksheets = []
|
10
|
+
@tables = []
|
11
|
+
@defined_names =[]
|
12
|
+
add_worksheet
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_worksheet
|
16
|
+
worksheet = Worksheet.new(self, worksheets.length + 1)
|
17
|
+
package.xl_rels.add_relationship(
|
18
|
+
REL_WORKSHEET,
|
19
|
+
"worksheets/sheet#{worksheet.index}.xml",
|
20
|
+
"rId#{worksheet.index}")
|
21
|
+
package.add_part "xl/worksheets/_rels/sheet#{worksheet.index}.xml.rels", worksheet.rels
|
22
|
+
package.add_part "xl/worksheets/sheet#{worksheet.index}.xml", worksheet
|
23
|
+
worksheets.push worksheet
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_table(table)
|
27
|
+
package.content_types.add_override "/xl/tables/#{table.filename}", TYPE_TABLE
|
28
|
+
package.add_part "xl/tables/#{table.filename}", table
|
29
|
+
tables.push table
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_defined_names(*defined_names)
|
33
|
+
defined_names.flatten.each do |attributes|
|
34
|
+
add_defined_name attributes
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_defined_name(attributes)
|
39
|
+
defined_names.push Xlsx::Elements::DefinedName.new(attributes[:name], attributes[:formula])
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_xml
|
43
|
+
build_standalone_xml do |xml|
|
44
|
+
xml.workbook(root_namespaces) {
|
45
|
+
xml.bookViews {
|
46
|
+
xml.workbookView
|
47
|
+
}
|
48
|
+
xml.sheets { worksheets.each { |worksheet|
|
49
|
+
xml.sheet(
|
50
|
+
"name" => worksheet.name,
|
51
|
+
"sheetId" => worksheet.index,
|
52
|
+
"r:id" => "rId#{worksheet.index}")
|
53
|
+
} }
|
54
|
+
xml.definedNames do
|
55
|
+
defined_names.each { |defined_name| defined_name.to_xml(xml) }
|
56
|
+
end if defined_names.any?
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def root_namespaces
|
64
|
+
{ "xmlns" => "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
65
|
+
"xmlns:r" => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' }
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module OpenXml
|
2
|
+
module Xlsx
|
3
|
+
module Parts
|
4
|
+
class Worksheet < OpenXml::Part
|
5
|
+
attr_reader :workbook, :index, :rows, :tables, :rels, :cell_ranges
|
6
|
+
|
7
|
+
def initialize(workbook, index)
|
8
|
+
@workbook = workbook
|
9
|
+
@index = index
|
10
|
+
@rows = []
|
11
|
+
@tables = []
|
12
|
+
@cell_ranges = []
|
13
|
+
@rels = OpenXml::Parts::Rels.new
|
14
|
+
@column_widths = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def column_widths(*args)
|
18
|
+
return @column_widths if args.none?
|
19
|
+
@column_widths = args.first
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_rows(*rows)
|
23
|
+
rows.flatten.each do |attributes|
|
24
|
+
add_row attributes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_row(attributes)
|
29
|
+
rows.push Xlsx::Elements::Row.new(self, attributes)
|
30
|
+
end
|
31
|
+
|
32
|
+
def merge_cells(*ranges)
|
33
|
+
ranges.each { |range| cell_ranges.push range }
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_table(id, name, ref, columns)
|
37
|
+
table = Xlsx::Parts::Table.new(id, name, ref, columns)
|
38
|
+
rels.add_relationship(REL_TABLE, "../tables/#{table.filename}")
|
39
|
+
workbook.add_table table
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_xml
|
43
|
+
build_standalone_xml do |xml|
|
44
|
+
xml.worksheet(root_namespaces) do
|
45
|
+
xml.sheetViews do
|
46
|
+
xml.sheetView(showGridLines: 0, tabSelected: 1, workbookViewId: 0)
|
47
|
+
end
|
48
|
+
xml.sheetFormatPr(baseColWidth: 10, defaultColWidth: 13.33203125, defaultRowHeight: 20, customHeight: 1)
|
49
|
+
xml.cols do
|
50
|
+
column_widths.each do |column, width|
|
51
|
+
xml.col(min: column, max: column, width: width, customWidth: 1)
|
52
|
+
end
|
53
|
+
end if column_widths.any?
|
54
|
+
xml.sheetData do
|
55
|
+
rows.each { |row| row.to_xml(xml) }
|
56
|
+
end
|
57
|
+
xml.mergeCells(count: merge_cells.size) do
|
58
|
+
cell_ranges.each { |range| xml.mergeCell ref: range }
|
59
|
+
end if cell_ranges.any?
|
60
|
+
xml.pageMargins(left: 0.75, right: 0.75, top: 1, bottom: 1, header: 0.5, footer: 0.5)
|
61
|
+
xml.pageSetup(orientation: "portrait", horizontalDpi: 4294967292, verticalDpi: 4294967292)
|
62
|
+
xml.tableParts(count: tables.count) do
|
63
|
+
tables.each do |rel|
|
64
|
+
xml.tablePart("r:id" => rel.id)
|
65
|
+
end
|
66
|
+
end if tables.any?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def name
|
72
|
+
"Sheet#{index}"
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def root_namespaces
|
78
|
+
{ "xmlns" => "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
79
|
+
"xmlns:r" => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
80
|
+
"xmlns:mc" => "http://schemas.openxmlformats.org/markup-compatibility/2006" }
|
81
|
+
end
|
82
|
+
|
83
|
+
def tables
|
84
|
+
rels.select { |rel| rel.type == REL_TABLE }
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|