1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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 123 124 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 152 153
|
package xlsx
import (
"database/sql"
"fmt"
"reflect"
"time"
)
// Writes an array to row r. Accepts a pointer to array type 'e',
// and writes the number of columns to write, 'cols'. If 'cols' is < 0,
// the entire array will be written if possible. Returns -1 if the 'e'
// doesn't point to an array, otherwise the number of columns written.
func (r *Row) WriteSlice(e interface{}, cols int) int {
if cols == 0 {
return cols
}
// make sure 'e' is a Ptr to Slice
v := reflect.ValueOf(e)
if v.Kind() != reflect.Ptr {
return -1
}
v = v.Elem()
if v.Kind() != reflect.Slice {
return -1
}
// it's a slice, so open up its values
n := v.Len()
if cols < n && cols > 0 {
n = cols
}
var setCell func(reflect.Value)
setCell = func(val reflect.Value) {
switch t := val.Interface().(type) {
case time.Time:
cell := r.AddCell()
cell.SetValue(t)
case fmt.Stringer: // check Stringer first
cell := r.AddCell()
cell.SetString(t.String())
case sql.NullString: // check null sql types nulls = ''
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetValue(t.String)
}
case sql.NullBool:
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetBool(t.Bool)
}
case sql.NullInt64:
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetValue(t.Int64)
}
case sql.NullFloat64:
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetValue(t.Float64)
}
default:
switch val.Kind() { // underlying type of slice
case reflect.String, reflect.Int, reflect.Int8,
reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, reflect.Float32:
cell := r.AddCell()
cell.SetValue(val.Interface())
case reflect.Bool:
cell := r.AddCell()
cell.SetBool(t.(bool))
case reflect.Interface:
setCell(reflect.ValueOf(t))
}
}
}
var i int
for i = 0; i < n; i++ {
setCell(v.Index(i))
}
return i
}
// Writes a struct to row r. Accepts a pointer to struct type 'e',
// and the number of columns to write, `cols`. If 'cols' is < 0,
// the entire struct will be written if possible. Returns -1 if the 'e'
// doesn't point to a struct, otherwise the number of columns written
func (r *Row) WriteStruct(e interface{}, cols int) int {
if cols == 0 {
return cols
}
v := reflect.ValueOf(e).Elem()
if v.Kind() != reflect.Struct {
return -1 // bail if it's not a struct
}
n := v.NumField() // number of fields in struct
if cols < n && cols > 0 {
n = cols
}
var k int
for i := 0; i < n; i, k = i+1, k+1 {
f := v.Field(i)
switch t := f.Interface().(type) {
case time.Time:
cell := r.AddCell()
cell.SetValue(t)
case fmt.Stringer: // check Stringer first
cell := r.AddCell()
cell.SetString(t.String())
case sql.NullString: // check null sql types nulls = ''
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetValue(t.String)
}
case sql.NullBool:
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetBool(t.Bool)
}
case sql.NullInt64:
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetValue(t.Int64)
}
case sql.NullFloat64:
cell := r.AddCell()
if cell.SetString(``); t.Valid {
cell.SetValue(t.Float64)
}
default:
switch f.Kind() {
case reflect.String, reflect.Int, reflect.Int8,
reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64, reflect.Float32:
cell := r.AddCell()
cell.SetValue(f.Interface())
case reflect.Bool:
cell := r.AddCell()
cell.SetBool(t.(bool))
default:
k-- // nothing set so reset to previous
}
}
}
return k
}
|