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)  } | 
