spreet 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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