spreet 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ module Spreet
3
+
4
+ # This class permit to manipulate coordinates in a table
5
+ class Coordinates
6
+ # Limit coordinates x and y in 0..65535 but coordinates are in one integer of 32 bits
7
+ X_BIT_SHIFT = 20 # ((RUBY_PLATFORM.match(/^[^\-]*[^\-0-9]64/) ? 64 : 32) / 2).freeze
8
+ # 2²⁰ rows = 1_048_576, 2¹² cols = 4_096,
9
+ Y_FILTER = ((1 << X_BIT_SHIFT) - 1).freeze
10
+
11
+ BASE_26_BEF = "0123456789abcdefghijklmnop"
12
+ BASE_26_AFT = "abcdefghijklmnopqrstuvwxyz"
13
+
14
+ attr_accessor :x, :y
15
+ def initialize(*args)
16
+ value = (args.size == 1 ? args[0] : args)
17
+ @x, @y = 0, 0
18
+ if value.is_a? String
19
+ if value.downcase.match(/^[a-z]+[0-9]+$/)
20
+ value = value.downcase.split(/([A-Z]+|[0-9]+)/).delete_if{|x| x.size.zero?}
21
+ @x, @y = value[0].tr(BASE_26_AFT, BASE_26_BEF).to_i(26), value[1].to_i(10)-1
22
+ elsif value.downcase.match(/^[0-9]+[^0-9]+[0-9]+$/)
23
+ value = value.downcase.split(/[^0-9]+/)
24
+ @x, @y = value[0].to_i(10), value[1].to_i(10)
25
+ end
26
+ elsif value.is_a? Integer
27
+ @x, @y = (value >> X_BIT_SHIFT), value & Y_FILTER
28
+ elsif value.is_a? Coordinates
29
+ @x, @y = value.x, value.y
30
+ elsif value.is_a? Array
31
+ @x, @y = value[0].to_i, value[1].to_i
32
+ elsif value.is_a? Hash
33
+ @x, @y = value[:x] || value[:column] || 0, value[:y] || value[:row] || 0
34
+ end
35
+ end
36
+
37
+ def to_s
38
+ @x.to_s(26).tr(BASE_26_BEF, BASE_26_AFT).upcase+(@y+1).to_s(10)
39
+ end
40
+
41
+ def to_a
42
+ [@x, @y]
43
+ end
44
+
45
+ def to_hash
46
+ {:x=>@x, :y=>@y}
47
+ end
48
+
49
+ def to_i
50
+ (@x << X_BIT_SHIFT) + @y
51
+ end
52
+
53
+ def ==(other_coordinate)
54
+ other_coordinate.x == self.x and other_coordinate.y == self.y
55
+ end
56
+
57
+ def <=>(other_coordinate)
58
+ self.to_i <=> other_coordinate.to_i
59
+ end
60
+ end
61
+
62
+ end
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require 'zip/zip'
3
+ require 'libxml'
3
4
 
4
5
  module Spreet
5
6
  module Handlers
@@ -11,9 +12,41 @@ module Spreet
11
12
  "Y" => "<number:year/>"
12
13
  }
13
14
 
15
+ MIME = {
16
+ :ods => "application/vnd.oasis.opendocument.spreadsheet",
17
+ :xml => "text/xml"
18
+ }.freeze.each{|n,ns| self.const_set("MIME_#{n}".upcase, ns.freeze)}
19
+
20
+
21
+ XMLNS = {
22
+ :manifest => 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0',
23
+ :office => 'urn:oasis:names:tc:opendocument:xmlns:office:1.0',
24
+ :style => 'urn:oasis:names:tc:opendocument:xmlns:style:1.0',
25
+ :text => 'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
26
+ :table => 'urn:oasis:names:tc:opendocument:xmlns:table:1.0',
27
+ :draw => 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0',
28
+ :fo => 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0',
29
+ :meta => 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0',
30
+ :number => 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0',
31
+ :presentation => 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0',
32
+ :svg => 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0',
33
+ :chart => 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0',
34
+ :dr3d => 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0',
35
+ :form => 'urn:oasis:names:tc:opendocument:xmlns:form:1.0',
36
+ :script => 'urn:oasis:names:tc:opendocument:xmlns:script:1.0',
37
+ :dc => 'http://purl.org/dc/elements/1.1/',
38
+ :ooo => 'http://openoffice.org/2004/office',
39
+ :ooow => 'http://openoffice.org/2004/writer',
40
+ :oooc => 'http://openoffice.org/2004/calc',
41
+ :math => 'http://www.w3.org/1998/Math/MathML',
42
+ :xlink => 'http://www.w3.org/1999/xlink',
43
+ :dom => 'http://www.w3.org/2001/xml-events',
44
+ :xsd => 'http://www.w3.org/2001/XMLSchema',
45
+ :xsi => 'http://www.w3.org/2001/XMLSchema-instance',
46
+ :xforms => 'http://www.w3.org/2002/xforms',
47
+ :field => 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0'
48
+ }.freeze.each{|n,ns| self.const_set("XMLNS_#{n}".upcase, ns.freeze)}
14
49
 
15
- def self.mimetype
16
- end
17
50
 
18
51
  def self.xmlec(string)
19
52
  zs = string.to_s.gsub('&', '&amp;').gsub('\'', '&apos;').gsub('<', '&lt;').gsub('>', '&gt;')
@@ -21,56 +54,302 @@ module Spreet
21
54
  return zs
22
55
  end
23
56
 
57
+ def self.add_attr(node, name, value, ns=nil)
58
+ attr = LibXML::XML::Attr.new(node, name, value.to_s)
59
+ attr.namespaces.namespace = ns if ns
60
+ return attr
61
+ end
62
+
63
+ def self.read(file, options={})
64
+ spreet = nil
65
+ Zip::ZipFile.open(file) do |zile|
66
+ # Check mime_type
67
+ entry = zile.find_entry "mimetype"
68
+ if entry.nil?
69
+ raise StandardError.new("First element in archive must be a non-compressed 'mimetype'-named file.")
70
+ else
71
+ mime_type = zile.read(entry)
72
+ unless mime_type == MIME_ODS
73
+ raise StandardError.new("Mimetype mismatch")
74
+ end
75
+ end
76
+
77
+ # Get manifest
78
+ entry, files = zile.find_entry("META-INF/manifest.xml"), {}
79
+ if entry.nil?
80
+ raise StandardError.new("Second element in archive must be a 'META-INF/manifest.xml'-named file.")
81
+ else
82
+ doc = LibXML::XML::Parser.string(zile.read(entry)).parse
83
+ for child in doc.root.children
84
+ if child.name == 'file-entry'
85
+ files[child["full-path"]] = child
86
+ end
87
+ end
88
+ end
89
+ if files["/"]["media-type"] != MIME_ODS
90
+ raise StandardError.new("Mimetype difference")
91
+ end
92
+
93
+ # Get content
94
+ if files["content.xml"] and entry = zile.find_entry("content.xml")
95
+ doc = LibXML::XML::Parser.string(zile.read(entry)).parse
96
+ unless doc.root.name == 'document-content'
97
+ raise StandardError.new("<document-content> element expected at root of content.xml")
98
+ end
99
+ if spreadsheet = doc.root.find('./office:body/office:spreadsheet', XMLNS_OFFICE).first
100
+ spreet = Spreet::Document.new()
101
+ for table in spreadsheet.find('./table:table', XMLNS_TABLE)
102
+ sheet = spreet.sheets.add(table["name"])
103
+ # Ignore table-column for now
104
+
105
+ rows = table.find("./table:table-rows").first || table
106
+ # # Expand rows and cells
107
+ # array = []
108
+ # for row in table.find('./table:table-row', XMLNS_TABLE)
109
+ # line = []
110
+ # for cell in row.find('./table:table-cell', XMLNS_TABLE)
111
+ # (cell["number-columns-repeated"]||'1').to_i.times do
112
+ # line << cell
113
+ # end
114
+ # end
115
+ # (row["number-rows-repeated"]||'1').to_i.times do
116
+ # array << line
117
+ # end
118
+ # end
119
+ # Fill sheet
120
+ row_offset = 0
121
+ rows.find('./table:table-row', XMLNS_TABLE).each_with_index do |row, y|
122
+ row_content, cell_offset = false, 0
123
+ row.find('./table:table-cell|./table:covered-table-cell', XMLNS_TABLE).each_with_index do |cell, x|
124
+ x += cell_offset
125
+ cell_content = false
126
+ if cell.name == "covered-table-cell"
127
+ # puts "covered-table-cell"
128
+ else
129
+ if value_type = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "value-type")
130
+ value_type = value_type.value.to_sym
131
+ p = cell.find('./text:p', XMLNS_TEXT).first
132
+ if [:float, :percentage].include?(value_type)
133
+ value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "value").value
134
+ sheet[x,y] = value.to_f
135
+ elsif value_type == :currency
136
+ value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "value").value
137
+ currency = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "currency").value
138
+ sheet[x,y] = Money.new(value, currency)
139
+ elsif value_type == :date
140
+ value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "date-value").value
141
+ if value.match(/\d{1,8}-\d{1,2}-\d{1,2}/)
142
+ value = Date.civil(*value.split(/[\-]+/).collect{|v| v.to_f})
143
+ elsif value.match(/\d{1,8}-\d{1,2}-\d{1,2}T\d{1,2}\:\d{1,2}\:\d{1,2}(\.\d+)?/)
144
+ value = Time.new(*value.split(/[\-\:\.\T]+/).collect{|v| v.to_f})
145
+ else
146
+ raise Exception.new("Bad date format")
147
+ end
148
+ sheet[x,y] = value
149
+ elsif value_type == :time
150
+ value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "time-value").value
151
+ sheet[x,y] = Duration.new(value)
152
+ elsif value_type == :boolean
153
+ value = cell.attributes.get_attribute_ns(XMLNS_OFFICE, "boolean-value").value
154
+ sheet[x,y] = (value == "true" ? true : false)
155
+ elsif value_type == :string
156
+ sheet[x,y] = p.content.to_s if p
157
+ end
158
+ sheet[x,y].text = p.content.to_s if p
159
+ cell_content = true
160
+ end
161
+ if annotation = cell.find("./office:annotation", XMLNS_OFFICE).first
162
+ if text = annotation.find("./text:p", XMLNS_TEXT).first
163
+ sheet[x,y].annotation = text.content.to_s
164
+ cell_content = true
165
+ end
166
+ end
167
+ end
168
+ repeated = (cell["number-columns-repeated"]||'1').to_i - 1
169
+ if repeated > 0
170
+ repeated.times do |i|
171
+ sheet[x+i+1,y] = sheet[x,y]
172
+ end if cell_content
173
+ cell_offset += repeated
174
+ end
175
+ row_content = true if cell_content
176
+ end
177
+
178
+ repeated = (row["number-rows-repeated"]||'1').to_i - 1
179
+ if repeated > 0
180
+ repeated.times do |i|
181
+ sheet.row(sheet.rows(y), :row=>(y+i+1))
182
+ end if row_content
183
+ row_offset += repeated
184
+ end
185
+
186
+ end
187
+ # What else ?
188
+ end
189
+ end
190
+ end
191
+
192
+ if spreet.nil?
193
+ raise StandardError.new("Missing or bad content.xml")
194
+ end
195
+ end
196
+ return spreet
197
+ end
198
+
24
199
 
25
200
  def self.write(spreet, file, options={})
26
201
  xml_escape = "to_s.gsub('&', '&amp;').gsub('\\'', '&apos;').gsub('<', '&lt;').gsub('>', '&gt;')"
27
202
  xml_escape << ".force_encoding('US-ASCII')" if xml_escape.respond_to?(:force_encoding)
28
- mimetype = "application/vnd.oasis.opendocument.spreadsheet"
203
+ mime_type = MIME_ODS
29
204
  # name = #{table.model.name}.model_name.human.gsub(/[^a-z0-9]/i,'_')
30
205
  Zip::ZipOutputStream.open(file) do |zile|
31
206
  # MimeType in first place
32
207
  zile.put_next_entry('mimetype', nil, nil, Zip::ZipEntry::STORED)
33
- zile << mimetype
208
+ zile << mime_type
34
209
 
35
210
  # Manifest
211
+ doc = LibXML::XML::Document.new
212
+ doc.root = LibXML::XML::Node.new('manifest')
213
+ ns = LibXML::XML::Namespace.new(doc.root, 'manifest', XMLNS_MANIFEST)
214
+ doc.root.namespaces.namespace = ns
215
+ files = {
216
+ "/" => {"media-type" => mime_type},
217
+ "content.xml" => {"media-type" => MIME_XML}
218
+ }
219
+ for path, attributes in files
220
+ doc.root << entry = LibXML::XML::Node.new('file-entry', nil, ns)
221
+ attributes['full-path'] = path
222
+ for name, value in attributes.sort
223
+ self.add_attr(entry, name, value, ns)
224
+ end
225
+ end
36
226
  zile.put_next_entry('META-INF/manifest.xml')
37
- zile << ("<?xml version=\"1.0\" encoding=\"UTF-8\"?><manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"><manifest:file-entry manifest:media-type=\"#{mimetype}\" manifest:full-path=\"/\"/><manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/></manifest:manifest>")
38
- zile.put_next_entry('content.xml')
39
-
40
- zile << ("<?xml version=\"1.0\" encoding=\"UTF-8\"?><office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:field=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0\" office:version=\"1.1\"><office:scripts/>")
41
- # Styles
42
- default_date_format = '%d/%m%Y' # ::I18n.translate("date.formats.default")
43
- zile << ("<office:automatic-styles><style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:use-optimal-column-width=\"true\"/></style:style><style:style style:name=\"header\" style:family=\"table-cell\"><style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"/></style:style><number:date-style style:name=\"K4D\" number:automatic-order=\"true\"><number:text>"+default_date_format.gsub(DATE_REGEXP){|x| "</number:text>"+DATE_ELEMENTS[x[1..1]]+"<number:text>"} +"</number:text></number:date-style><style:style style:name=\"ce1\" style:family=\"table-cell\" style:data-style-name=\"K4D\"/></office:automatic-styles>")
44
-
45
- zile << ("<office:body><office:spreadsheet>")
46
- # Tables
227
+ xml = doc.to_s(:indent=>false)
228
+ xml.force_encoding('US-ASCII') if xml.respond_to? :force_encoding
229
+ zile << xml
230
+
231
+ # Content
232
+ doc = LibXML::XML::Document.new
233
+ doc.root = LibXML::XML::Node.new('document-content')
234
+ nss = {}
235
+ for prefix, ns in XMLNS.select{|k,v| k != :manifest}
236
+ nss[prefix] = LibXML::XML::Namespace.new(doc.root, prefix.to_s, ns)
237
+ end
238
+ doc.root.namespaces.namespace = nss[:office]
239
+ add_attr(doc.root, "version", "1.1", nss[:office])
240
+
241
+ doc.root << automatic_styles = LibXML::XML::Node.new("automatic-styles", nil, nss[:office])
242
+
243
+ automatic_styles << style = LibXML::XML::Node.new("date-style", nil, nss[:number])
244
+ add_attr(style, "name", "DMY", nss[:style])
245
+ add_attr(style, "automatic-order", "true", nss[:number])
246
+ style << token = LibXML::XML::Node.new("day", nil, nss[:number])
247
+ add_attr(token, "style", "long", nss[:number])
248
+ style << token = LibXML::XML::Node.new("text", "/", nss[:number])
249
+ style << token = LibXML::XML::Node.new("month", nil, nss[:number])
250
+ add_attr(token, "style", "long", nss[:number])
251
+ style << token = LibXML::XML::Node.new("text", "/", nss[:number])
252
+ style << token = LibXML::XML::Node.new("year", nil, nss[:number])
253
+
254
+ automatic_styles << style = LibXML::XML::Node.new("style", nil, nss[:style])
255
+ add_attr(style, "name", "CE1", nss[:style])
256
+ add_attr(style, "family", "table-cell", nss[:style])
257
+ add_attr(style, "data-style-name", "DMY", nss[:style])
258
+
259
+ automatic_styles << style = LibXML::XML::Node.new("style", nil, nss[:number])
260
+ add_attr(style, "name", "COL", nss[:style])
261
+ add_attr(style, "family", "table-column", nss[:number])
262
+ style << token = LibXML::XML::Node.new("table-column-properties", nil, nss[:style])
263
+ add_attr(token, "break-before", "auto", nss[:fo])
264
+ add_attr(token, "use-optimal-column-width", "true", nss[:style])
265
+
266
+ doc.root << body = LibXML::XML::Node.new("body", nil, nss[:office])
267
+ body << spreadsheet = LibXML::XML::Node.new("spreadsheet", nil, nss[:office])
47
268
  for sheet in spreet.sheets
48
- zile << ("<table:table table:name=\"#{xmlec(sheet.name)}\">")
49
- zile << ("<table:table-column table:number-columns-repeated=\"#{sheet.bound.x+1}\"/>")
50
- # zile << ("<table:table-header-rows><table:table-row>"+columns_headers(table).collect{|h| "<table:table-cell table:style-name=\"header\" office:value-type=\"string\"><text:p>'+(#{h}).#{xml_escape}+'</text:p></table:table-cell>"}.join+"</table:table-row></table:table-header-rows>")
269
+ spreadsheet << table = LibXML::XML::Node.new("table", nil, nss[:table])
270
+ add_attr(table, "name", sheet.name, nss[:table])
271
+ table << table_columns = LibXML::XML::Node.new("table-columns", nil, nss[:table])
272
+ for x in 0..sheet.bound.x
273
+ table_columns << table_column = LibXML::XML::Node.new("table-column", nil, nss[:table])
274
+ add_attr(table_column, "style-name", "COL", nss[:table])
275
+ end
276
+ table << table_rows = LibXML::XML::Node.new("table-rows", nil, nss[:table])
51
277
  sheet.each_row do |row| # #{record} in #{table.records_variable_name}\n"
52
- zile << "<table:table-row>"
278
+ table_rows << table_row = LibXML::XML::Node.new("table-row", nil, nss[:table])
53
279
  for cell in row
54
- zile << "<table:table-cell"+(if cell.type == :decimal
55
- " office:value-type=\"float\" office:value=\"#{xmlec(cell.value)}\""
56
- elsif cell.type == :boolean
57
- " office:value-type=\"boolean\" office:boolean-value=\"#{xmlec(cell.value ? 'true' : 'false')}\""
58
- elsif cell.type == :date
59
- " office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"#{xmlec(cell.value)}\""
60
- else
61
- " office:value-type=\"string\""
62
- end)+"><text:p>"+xmlec(cell.text)+"</text:p></table:table-cell>"
280
+ table_row << table_cell = LibXML::XML::Node.new("table-cell", nil, nss[:table])
281
+ unless cell.empty?
282
+ add_attr(table_cell, "value-type", cell.type, nss[:office])
283
+ if cell.type == :float # or percentage
284
+ add_attr(table_cell, "value", cell.value, nss[:office])
285
+ elsif cell.type == :currency
286
+ add_attr(table_cell, "value", cell.value.to_f, nss[:office])
287
+ add_attr(table_cell, "currency", cell.value.currency_as_string, nss[:office])
288
+ elsif cell.type == :date
289
+ if cell.value.is_a? Date
290
+ add_attr(table_cell, "date-value", cell.value.to_s, nss[:office])
291
+ add_attr(table_cell, "style-name", "CE1", nss[:table])
292
+ elsif cell.value.is_a?(DateTime) or cell.value.is_a?(Time)
293
+ add_attr(table_cell, "datetime-value", cell.value.to_xsd, nss[:office])
294
+ end
295
+ elsif cell.type == :time
296
+ add_attr(table_cell, "time-value", cell.value.to_s, nss[:office])
297
+ elsif cell.type == :boolean
298
+ add_attr(table_cell, "boolean-value", cell.value.to_s, nss[:office])
299
+ end
300
+ table_cell << LibXML::XML::Node.new("p", cell.text, nss[:text])
301
+ end
302
+ unless cell.annotation.nil?
303
+ table_cell << annotation = LibXML::XML::Node.new("annotation", nil, nss[:office])
304
+ annotation << LibXML::XML::Node.new("p", cell.annotation, nss[:text])
305
+ end
63
306
  end
64
- zile << "</table:table-row>"
65
307
  end
66
- zile << ("</table:table>")
67
308
  end
68
- zile << ("</office:spreadsheet></office:body></office:document-content>")
309
+
310
+ zile.put_next_entry('content.xml')
311
+ xml = doc.to_s(:indent=>false)
312
+ xml.force_encoding('US-ASCII') if xml.respond_to? :force_encoding
313
+ zile << xml
314
+
315
+ # zile.put_next_entry('content.xml')
316
+ # zile << ("<?xml version=\"1.0\" encoding=\"UTF-8\"?><office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:field=\"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0\" office:version=\"1.1\"><office:scripts/>")
317
+ # # Styles
318
+ # default_date_format = '%d/%m%Y' # ::I18n.translate("date.formats.default")
319
+ # zile << ("<office:automatic-styles><style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:use-optimal-column-width=\"true\"/></style:style><style:style style:name=\"header\" style:family=\"table-cell\"><style:text-properties fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"/></style:style><number:date-style style:name=\"K4D\" number:automatic-order=\"true\"><number:text>"+default_date_format.gsub(DATE_REGEXP){|x| "</number:text>"+DATE_ELEMENTS[x[1..1]]+"<number:text>"} +"</number:text></number:date-style><style:style style:name=\"ce1\" style:family=\"table-cell\" style:data-style-name=\"K4D\"/></office:automatic-styles>")
320
+
321
+ # zile << ("<office:body><office:spreadsheet>")
322
+ # # Tables
323
+ # for sheet in spreet.sheets
324
+ # zile << ("<table:table table:name=\"#{xmlec(sheet.name)}\">")
325
+ # zile << ("<table:table-column table:number-columns-repeated=\"#{sheet.bound.x+1}\"/>")
326
+ # # zile << ("<table:table-header-rows><table:table-row>"+columns_headers(table).collect{|h| "<table:table-cell table:style-name=\"header\" office:value-type=\"string\"><text:p>'+(#{h}).#{xml_escape}+'</text:p></table:table-cell>"}.join+"</table:table-row></table:table-header-rows>")
327
+ # sheet.each_row do |row| # #{record} in #{table.records_variable_name}\n"
328
+ # zile << "<table:table-row>"
329
+ # for cell in row
330
+ # if cell.empty?
331
+ # zile << "<table:table-cell/>"
332
+ # else
333
+ # zile << "<table:table-cell"+(if cell.type == :decimal
334
+ # " office:value-type=\"float\" office:value=\"#{xmlec(cell.value)}\""
335
+ # elsif cell.type == :boolean
336
+ # " office:value-type=\"boolean\" office:boolean-value=\"#{xmlec(cell.value ? 'true' : 'false')}\""
337
+ # elsif cell.type == :date
338
+ # " office:value-type=\"date\" table:style-name=\"ce1\" office:date-value=\"#{xmlec(cell.value)}\""
339
+ # else
340
+ # " office:value-type=\"string\""
341
+ # end)+"><text:p>"+xmlec(cell.text)+"</text:p></table:table-cell>"
342
+ # end
343
+ # end
344
+ # zile << "</table:table-row>"
345
+ # end
346
+ # zile << ("</table:table>")
347
+ # end
348
+ # zile << ("</office:spreadsheet></office:body></office:document-content>")
69
349
  end
70
350
  # Zile is finished
71
351
  end
72
352
 
73
-
74
353
  end
75
354
  end
76
355
  end
@@ -0,0 +1,13 @@
1
+ # encoding: UTF-8
2
+
3
+ class ::Time
4
+
5
+ def to_xsd
6
+ if self.utc?
7
+ self.strftime("%Y-%m-%dT%H:%M:%S")
8
+ else
9
+ self.strftime("%Y-%m-%dT%H:%M:%S%z")
10
+ end
11
+ end
12
+
13
+ end