diff options
author | George Abbott <otg@gabbott.dev> | 2023-06-15 22:17:12 +0100 |
---|---|---|
committer | George Abbott <otg@gabbott.dev> | 2023-06-15 22:17:12 +0100 |
commit | 9987f77b7100bb5934faa7427d1a4acda866ff38 (patch) | |
tree | 6aa4da902be7f6af0d2926accd151b949f92d81d /rows_generic.go | |
parent | c4d71b0fdb4bef63e1553843efa9cb9ea9270806 (diff) |
excelize -> anyxcelizegetRowInterface
Diffstat (limited to 'rows_generic.go')
-rw-r--r-- | rows_generic.go | 259 |
1 files changed, 253 insertions, 6 deletions
diff --git a/rows_generic.go b/rows_generic.go index fff3019..87f4087 100644 --- a/rows_generic.go +++ b/rows_generic.go @@ -1,10 +1,10 @@ -package excelize +package anyxcelize import ( - // "bytes" + "bytes" "encoding/xml" "errors" - // "fmt" + "fmt" // "io" // "math" "strings" @@ -14,6 +14,226 @@ import ( // "github.com/mohae/deepcopy" ) +// Functions: cols + +// Rows return the current column's row values. +func (cols *ColsGeneric) RowsGeneric(opts ...Options) ([]any, error) { + var rowIterator rowXMLIteratorGeneric + if cols.stashCol >= cols.curCol { + return rowIterator.cells, rowIterator.err + } + cols.rawCellValue = parseOptions(opts...).RawCellValue + if cols.sst, rowIterator.err = cols.f.sharedStringsReader(); rowIterator.err != nil { + return rowIterator.cells, rowIterator.err + } + decoder := cols.f.xmlNewDecoder(bytes.NewReader(cols.sheetXML)) + for { + token, _ := decoder.Token() + if token == nil { + break + } + switch xmlElement := token.(type) { + case xml.StartElement: + rowIterator.inElement = xmlElement.Name.Local + if rowIterator.inElement == "row" { + rowIterator.cellCol = 0 + rowIterator.cellRow++ + attrR, _ := attrValToInt("r", xmlElement.Attr) + if attrR != 0 { + rowIterator.cellRow = attrR + } + } + if cols.rowXMLHandlerGeneric(&rowIterator, &xmlElement, decoder); rowIterator.err != nil { + return rowIterator.cells, rowIterator.err + } + case xml.EndElement: + if xmlElement.Name.Local == "sheetData" { + return rowIterator.cells, rowIterator.err + } + } + } + return rowIterator.cells, rowIterator.err +} + +func (f *File) ColsGeneric(sheet string) (*ColsGeneric, error) { + name, ok := f.getSheetXMLPath(sheet) + if !ok { + return nil, ErrSheetNotExist{sheet} + } + if ws, ok := f.Sheet.Load(name); ok && ws != nil { + worksheet := ws.(*xlsxWorksheet) + worksheet.Lock() + defer worksheet.Unlock() + output, _ := xml.Marshal(worksheet) + f.saveFileList(name, f.replaceNameSpaceBytes(name, output)) + } + var colIterator columnXMLIteratorGeneric // do me ! + colIterator.cols.sheetXML = f.readBytes(name) + decoder := f.xmlNewDecoder(bytes.NewReader(colIterator.cols.sheetXML)) + for { + token, _ := decoder.Token() + if token == nil { + break + } + switch xmlElement := token.(type) { + case xml.StartElement: + columnXMLHandlerGeneric(&colIterator, &xmlElement) + if colIterator.err != nil { + return &colIterator.cols, colIterator.err + } + case xml.EndElement: + if xmlElement.Name.Local == "sheetData" { + colIterator.cols.f = f + colIterator.cols.sheet = trimSheetName(sheet) + return &colIterator.cols, nil + } + } + } + return &colIterator.cols, nil +} + +// columnXMLHandler parse the column XML element of the worksheet. +func columnXMLHandlerGeneric(colIterator *columnXMLIteratorGeneric, xmlElement *xml.StartElement) { + colIterator.err = nil + inElement := xmlElement.Name.Local + if inElement == "row" { + colIterator.row++ + for _, attr := range xmlElement.Attr { + if attr.Name.Local == "r" { + if colIterator.curRow, colIterator.err = strconv.Atoi(attr.Value); colIterator.err != nil { + return + } + colIterator.row = colIterator.curRow + } + } + colIterator.cols.totalRows = colIterator.row + colIterator.cellCol = 0 + } + if inElement == "c" { + colIterator.cellCol++ + for _, attr := range xmlElement.Attr { + if attr.Name.Local == "r" { + if colIterator.cellCol, _, colIterator.err = CellNameToCoordinates(attr.Value); colIterator.err != nil { + return + } + } + } + if colIterator.cellCol > colIterator.cols.totalCols { + colIterator.cols.totalCols = colIterator.cellCol + } + } +} + + +// columnXMLIterator defined runtime use field for the worksheet column SAX parser. +type columnXMLIteratorGeneric struct { + err error + cols ColsGeneric + cellCol, curRow, row int +} + +type ColsGeneric struct { + err error + curCol, totalCols, totalRows, stashCol int + rawCellValue bool + sheet string + f *File + sheetXML []byte + sst *xlsxSST +} + +// rowXMLHandler parse the row XML element of the worksheet. +func (cols *ColsGeneric) rowXMLHandlerGeneric(rowIterator *rowXMLIteratorGeneric, xmlElement *xml.StartElement, decoder *xml.Decoder) { + if rowIterator.inElement == "c" { + rowIterator.cellCol++ + for _, attr := range xmlElement.Attr { + if attr.Name.Local == "r" { + if rowIterator.cellCol, rowIterator.cellRow, rowIterator.err = CellNameToCoordinates(attr.Value); rowIterator.err != nil { + return + } + } + } + blank := rowIterator.cellRow - len(rowIterator.cells) + for i := 1; i < blank; i++ { + rowIterator.cells = append(rowIterator.cells, "") + } + if rowIterator.cellCol == cols.curCol { + colCell := xlsxC{} + _ = decoder.DecodeElement(&colCell, xmlElement) + val, _ := colCell.getValueFrom(cols.f, cols.sst, cols.rawCellValue) + rowIterator.cells = append(rowIterator.cells, val) + } + } +} +func (f *File) GetColsGeneric(sheet string, opts ...Options) ([][]any, error) { + cols, err := f.ColsGeneric(sheet) + if err != nil { + return nil, err + } + results := make([][]any, 0, 64) + for cols.Next() { + col, _ := cols.RowsGeneric(opts...) + results = append(results, col) + } + return results, nil +} + + +// Next will return true if the next column is found. +func (cols *ColsGeneric) Next() bool { + cols.curCol++ + return cols.curCol <= cols.totalCols +} + +// Error will return an error when the error occurs. +func (cols *ColsGeneric) Error() error { + return cols.err +} + +// Rows return the current column's row values. +func (cols *ColsGeneric) Rows(opts ...Options) ([]any, error) { + var rowIterator rowXMLIteratorGeneric + if cols.stashCol >= cols.curCol { + return rowIterator.cells, rowIterator.err + } + cols.rawCellValue = parseOptions(opts...).RawCellValue + if cols.sst, rowIterator.err = cols.f.sharedStringsReader(); rowIterator.err != nil { + return rowIterator.cells, rowIterator.err + } + decoder := cols.f.xmlNewDecoder(bytes.NewReader(cols.sheetXML)) + for { + token, _ := decoder.Token() + if token == nil { + break + } + switch xmlElement := token.(type) { + case xml.StartElement: + rowIterator.inElement = xmlElement.Name.Local + if rowIterator.inElement == "row" { + rowIterator.cellCol = 0 + rowIterator.cellRow++ + attrR, _ := attrValToInt("r", xmlElement.Attr) + if attrR != 0 { + rowIterator.cellRow = attrR + } + } + if cols.rowXMLHandlerGeneric(&rowIterator, &xmlElement, decoder); rowIterator.err != nil { + return rowIterator.cells, rowIterator.err + } + case xml.EndElement: + if xmlElement.Name.Local == "sheetData" { + return rowIterator.cells, rowIterator.err + } + } + } + return rowIterator.cells, rowIterator.err +} + + + + +// Functions: rows + func (f *File) GetRowsGeneric(sheet string, opts ...Options) ([][]any, error) { rows, err := f.RowsGeneric(sheet) if err != nil { @@ -194,8 +414,10 @@ func (c *xlsxC) getValueFromGeneric(f *File, d *xlsxSST, raw bool) (any, error) defer f.Unlock() switch c.T { case "b": // done, not tested + // fmt.Println("Calling c.getcellBoolGeneric") return c.getCellBoolGeneric(f, raw) case "d": // done, not tested + // fmt.Println("Calling c.getCellDateGeneric") return c.getCellDateGeneric(f, raw) case "s": // Don't touch, strings are a-ok if c.V != "" { @@ -216,6 +438,7 @@ func (c *xlsxC) getValueFromGeneric(f *File, d *xlsxSST, raw bool) (any, error) return f.formattedValue(c.S, c.V, raw) default: // For integrals and floatings? These need to go into int or float64. // We need to change it to return an int or a decimal. + // fmt.Println("Calling c.getCellNumeric") return c.getCellNumeric(f, raw) // if isNum, precision, decimal := isNumeric(c.V); isNum && !raw { // if precision > 15 { @@ -239,7 +462,7 @@ func (c *xlsxC) getCellBoolGeneric(f *File, raw bool) (any, error) { return false, nil } - return f.formattedValue(c.S, c.V, raw) + return f.formattedValueGeneric(c.S, c.V, raw) } // TODO: I probably actually have to like, do something, to get a valid @@ -253,6 +476,7 @@ func (c *xlsxC) getCellBoolGeneric(f *File, raw bool) (any, error) { // function not to call formattedValue, and just to return a proper date like // it should. I don't want to return a float64, but a time.Time I believe. func (c *xlsxC) getCellDateGeneric(f *File, raw bool) (time.Time, error) { + fmt.Printf("getCellDateGeneric with date %v\n", c.V) // if !raw { layout := "20060102T150405.999" if strings.HasSuffix(c.V, "Z") { @@ -284,18 +508,41 @@ func (c *xlsxC) getCellDateGeneric(f *File, raw bool) (time.Time, error) { // For now, we could just try parse as a float, and if it doesn't work parse as // an int, and if it doesn't work cry. func (c *xlsxC) getCellNumeric(f *File, raw bool) (any, error) { + // fmt.Printf("rows.getCellNumeric with value %v\n", c.V) // This can either be a float or an int. If it is a float, return a // float64. Otherwise, return an int. /* TODO: implement according to above comment. */ if isNum, precision, decimal := isNumeric(c.V); isNum && !raw { + // fmt.Printf("isNum true, prec{%v} ; decimal(%v)\n", precision, decimal) + + /* new way, see comment below */ + /* 2023-02-28: I'm commenting this out to try have it call + * formattedValueGeneric, which should (?) solve my worries. */ + // v, err := strconv.ParseInt(c.V, 10, 64) + // if err != nil { + // return strconv.ParseFloat(c.V, 64) + // } + // return v, err + + + if precision > 15 { + // We actually just need a way to return a float. I + // say try return int first, if it doesn't work try + // float, else cry and die. // Return here a float64 + // r, err := strconv.ParseFloat(c.V, 64) + // fmt.Printf("prec15: ret(%v)\n", r) + // return r, err c.V = strconv.FormatFloat(decimal, 'G', 15, 64) } else { // I think, return here an int? + // return strconv.ParseInt(c.V, 10, 64) c.V = strconv.FormatFloat(decimal, 'f', -1, 64) } - } - return f.formattedValue(c.S, c.V, raw) + } + // fmt.Printf("getCellNumeric is failing, value %v\n", c.V) + // return nil, errors.New("getCellNumeric failed like") + return f.formattedValueGeneric(c.S, c.V, raw) } |