cell.go 6.9 KB
Newer Older
xurime's avatar
xurime 已提交
1 2 3 4 5 6 7 8
package excelize

import (
	"encoding/xml"
	"strconv"
	"strings"
)

9
// GetCellValue provides function to get value from cell by given sheet index
10
// and axis in XLSX file.
11
func (f *File) GetCellValue(sheet, axis string) string {
xurime's avatar
xurime 已提交
12
	xlsx := f.workSheetReader(sheet)
xurime's avatar
xurime 已提交
13
	axis = strings.ToUpper(axis)
14 15 16 17 18 19 20 21 22
	if xlsx.MergeCells != nil {
		for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
			if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
				axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
			}
		}
	}
	row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
	xAxis := row - 1
xurime's avatar
xurime 已提交
23
	rows := len(xlsx.SheetData.Row)
xurime's avatar
xurime 已提交
24 25 26 27 28 29
	if rows > 1 {
		lastRow := xlsx.SheetData.Row[rows-1].R
		if lastRow >= rows {
			rows = lastRow
		}
	}
30
	if rows < xAxis {
31
		return ""
xurime's avatar
xurime 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45
	}
	for _, v := range xlsx.SheetData.Row {
		if v.R != row {
			continue
		}
		for _, r := range v.C {
			if axis != r.R {
				continue
			}
			switch r.T {
			case "s":
				shardStrings := xlsxSST{}
				xlsxSI := 0
				xlsxSI, _ = strconv.Atoi(r.V)
46
				xml.Unmarshal([]byte(f.readXML("xl/sharedStrings.xml")), &shardStrings)
xurime's avatar
xurime 已提交
47 48 49 50 51 52 53 54
				return shardStrings.SI[xlsxSI].T
			case "str":
				return r.V
			default:
				return r.V
			}
		}
	}
55
	return ""
xurime's avatar
xurime 已提交
56 57
}

58 59
// GetCellFormula provides function to get formula from cell by given sheet
// index and axis in XLSX file.
60
func (f *File) GetCellFormula(sheet, axis string) string {
xurime's avatar
xurime 已提交
61
	xlsx := f.workSheetReader(sheet)
xurime's avatar
xurime 已提交
62
	axis = strings.ToUpper(axis)
63 64 65 66 67 68 69 70 71
	if xlsx.MergeCells != nil {
		for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
			if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
				axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
			}
		}
	}
	row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
	xAxis := row - 1
xurime's avatar
xurime 已提交
72 73 74 75 76 77 78
	rows := len(xlsx.SheetData.Row)
	if rows > 1 {
		lastRow := xlsx.SheetData.Row[rows-1].R
		if lastRow >= rows {
			rows = lastRow
		}
	}
79
	if rows < xAxis {
80
		return ""
xurime's avatar
xurime 已提交
81
	}
xurime's avatar
xurime 已提交
82 83 84 85 86 87 88 89 90 91
	for _, v := range xlsx.SheetData.Row {
		if v.R != row {
			continue
		}
		for _, f := range v.C {
			if axis != f.R {
				continue
			}
			if f.F != nil {
				return f.F.Content
xurime's avatar
xurime 已提交
92 93 94
			}
		}
	}
95
	return ""
xurime's avatar
xurime 已提交
96
}
97 98 99 100

// SetCellFormula provides function to set cell formula by given string and
// sheet index.
func (f *File) SetCellFormula(sheet, axis, formula string) {
xurime's avatar
xurime 已提交
101
	xlsx := f.workSheetReader(sheet)
102
	axis = strings.ToUpper(axis)
103 104 105 106 107 108 109
	if xlsx.MergeCells != nil {
		for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
			if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
				axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
			}
		}
	}
110 111 112 113 114 115 116 117
	col := string(strings.Map(letterOnlyMapF, axis))
	row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
	xAxis := row - 1
	yAxis := titleToNumber(col)

	rows := xAxis + 1
	cell := yAxis + 1

xurime's avatar
xurime 已提交
118 119
	completeRow(xlsx, rows, cell)
	completeCol(xlsx, rows, cell)
120 121 122 123 124 125 126 127 128 129

	if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
		xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
	} else {
		f := xlsxF{
			Content: formula,
		}
		xlsx.SheetData.Row[xAxis].C[yAxis].F = &f
	}
}
130 131 132 133

// SetCellHyperLink provides function to set cell hyperlink by given sheet index
// and link URL address. Only support external link currently.
func (f *File) SetCellHyperLink(sheet, axis, link string) {
xurime's avatar
xurime 已提交
134
	xlsx := f.workSheetReader(sheet)
135
	axis = strings.ToUpper(axis)
136 137 138 139 140 141 142
	if xlsx.MergeCells != nil {
		for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
			if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
				axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
			}
		}
	}
143 144 145 146 147 148 149 150 151 152 153 154 155
	rID := f.addSheetRelationships(sheet, SourceRelationshipHyperLink, link, "External")
	hyperlink := xlsxHyperlink{
		Ref: axis,
		RID: "rId" + strconv.Itoa(rID),
	}
	if xlsx.Hyperlinks != nil {
		xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, hyperlink)
	} else {
		hyperlinks := xlsxHyperlinks{}
		hyperlinks.Hyperlink = append(hyperlinks.Hyperlink, hyperlink)
		xlsx.Hyperlinks = &hyperlinks
	}
}
xurime's avatar
xurime 已提交
156

157 158
// MergeCell provides function to merge cells by given coordinate area and sheet
// name. For example create a merged cell of D3:E9 on Sheet1:
xurime's avatar
xurime 已提交
159
//
160
//    xlsx.MergeCell("sheet1", "D3", "E9")
xurime's avatar
xurime 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
//
// If you create a merged cell that overlaps with another existing merged cell,
// those merged cells that already exist will be removed.
func (f *File) MergeCell(sheet, hcell, vcell string) {
	if hcell == vcell {
		return
	}

	hcell = strings.ToUpper(hcell)
	vcell = strings.ToUpper(vcell)

	// Coordinate conversion, convert C1:B3 to 2,0,1,2.
	hcol := string(strings.Map(letterOnlyMapF, hcell))
	hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell))
	hyAxis := hrow - 1
	hxAxis := titleToNumber(hcol)

	vcol := string(strings.Map(letterOnlyMapF, vcell))
	vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell))
	vyAxis := vrow - 1
	vxAxis := titleToNumber(vcol)

	if vxAxis < hxAxis {
		hcell, vcell = vcell, hcell
		vxAxis, hxAxis = hxAxis, vxAxis
	}

	if vyAxis < hyAxis {
		hcell, vcell = vcell, hcell
		vyAxis, hyAxis = hyAxis, vyAxis
	}

xurime's avatar
xurime 已提交
193
	xlsx := f.workSheetReader(sheet)
xurime's avatar
xurime 已提交
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	if xlsx.MergeCells != nil {
		mergeCell := xlsxMergeCell{}
		// Correct the coordinate area, such correct C1:B3 to B1:C3.
		mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1)
		// Delete the merged cells of the overlapping area.
		for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
			if checkCellInArea(hcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0], mergeCell.Ref) {
				xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
			} else if checkCellInArea(vcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[1], mergeCell.Ref) {
				xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
			}
		}
		xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &mergeCell)
	} else {
		mergeCell := xlsxMergeCell{}
		// Correct the coordinate area, such correct C1:B3 to B1:C3.
		mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1)
		mergeCells := xlsxMergeCells{}
		mergeCells.Cells = append(mergeCells.Cells, &mergeCell)
		xlsx.MergeCells = &mergeCells
	}
}

// checkCellInArea provides function to determine if a given coordinate is
// within an area.
func checkCellInArea(cell, area string) bool {
	result := false
	cell = strings.ToUpper(cell)
	col := string(strings.Map(letterOnlyMapF, cell))
	row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
	xAxis := row - 1
	yAxis := titleToNumber(col)

	ref := strings.Split(area, ":")
	hCol := string(strings.Map(letterOnlyMapF, ref[0]))
	hRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[0]))
	hyAxis := hRow - 1
	hxAxis := titleToNumber(hCol)

	vCol := string(strings.Map(letterOnlyMapF, ref[1]))
	vRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[1]))
	vyAxis := vRow - 1
	vxAxis := titleToNumber(vCol)

	if hxAxis <= yAxis && yAxis <= vxAxis && hyAxis <= xAxis && xAxis <= vyAxis {
		result = true
	}

	return result
}