read.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package xlsx
  2. import (
  3. "errors"
  4. "reflect"
  5. "strconv"
  6. "time"
  7. )
  8. var (
  9. errNilInterface = errors.New("nil pointer is not a valid argument")
  10. errNotStructPointer = errors.New("argument must be a pointer to struct")
  11. errInvalidTag = errors.New(`invalid tag: must have the format xlsx:idx`)
  12. )
  13. //XLSXUnmarshaler is the interface implemented for types that can unmarshal a Row
  14. //as a representation of themselves.
  15. type XLSXUnmarshaler interface {
  16. Unmarshal(*Row) error
  17. }
  18. //ReadStruct reads a struct from r to ptr. Accepts a ptr
  19. //to struct. This code expects a tag xlsx:"N", where N is the index
  20. //of the cell to be used. Basic types like int,string,float64 and bool
  21. //are supported
  22. func (r *Row) ReadStruct(ptr interface{}) error {
  23. if ptr == nil {
  24. return errNilInterface
  25. }
  26. //check if the type implements XLSXUnmarshaler. If so,
  27. //just let it do the work.
  28. unmarshaller, ok := ptr.(XLSXUnmarshaler)
  29. if ok {
  30. return unmarshaller.Unmarshal(r)
  31. }
  32. v := reflect.ValueOf(ptr)
  33. if v.Kind() != reflect.Ptr {
  34. return errNotStructPointer
  35. }
  36. v = v.Elem()
  37. if v.Kind() != reflect.Struct {
  38. return errNotStructPointer
  39. }
  40. n := v.NumField()
  41. for i := 0; i < n; i++ {
  42. field := v.Type().Field(i)
  43. idx := field.Tag.Get("xlsx")
  44. //do a recursive check for the field if it is a struct or a pointer
  45. //even if it doesn't have a tag
  46. //ignore if it has a - or empty tag
  47. isTime := false
  48. switch {
  49. case idx == "-":
  50. continue
  51. case field.Type.Kind() == reflect.Ptr || field.Type.Kind() == reflect.Struct:
  52. var structPtr interface{}
  53. if !v.Field(i).CanSet() {
  54. continue
  55. }
  56. if field.Type.Kind() == reflect.Struct {
  57. structPtr = v.Field(i).Addr().Interface()
  58. } else {
  59. structPtr = v.Field(i).Interface()
  60. }
  61. //check if the container is a time.Time
  62. _, isTime = structPtr.(*time.Time)
  63. if isTime {
  64. break
  65. }
  66. err := r.ReadStruct(structPtr)
  67. if err != nil {
  68. return err
  69. }
  70. continue
  71. case len(idx) == 0:
  72. continue
  73. }
  74. pos, err := strconv.Atoi(idx)
  75. if err != nil {
  76. return errInvalidTag
  77. }
  78. //check if desired position is not out of bounds
  79. if pos > len(r.Cells)-1 {
  80. continue
  81. }
  82. cell := r.Cells[pos]
  83. fieldV := v.Field(i)
  84. //continue if the field is not settable
  85. if !fieldV.CanSet() {
  86. continue
  87. }
  88. if isTime {
  89. t, err := cell.GetTime(false)
  90. if err != nil {
  91. return err
  92. }
  93. if field.Type.Kind() == reflect.Ptr {
  94. fieldV.Set(reflect.ValueOf(&t))
  95. } else {
  96. fieldV.Set(reflect.ValueOf(t))
  97. }
  98. continue
  99. }
  100. switch field.Type.Kind() {
  101. case reflect.String:
  102. value, err := cell.FormattedValue()
  103. if err != nil {
  104. return err
  105. }
  106. fieldV.SetString(value)
  107. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  108. value, err := cell.Int64()
  109. if err != nil {
  110. return err
  111. }
  112. fieldV.SetInt(value)
  113. case reflect.Float64:
  114. value, err := cell.Float()
  115. if err != nil {
  116. return err
  117. }
  118. fieldV.SetFloat(value)
  119. case reflect.Bool:
  120. value := cell.Bool()
  121. fieldV.SetBool(value)
  122. }
  123. }
  124. value := v.Interface()
  125. ptr = &value
  126. return nil
  127. }