OSDN Git Service

Speed up merge cells
authorthree <three3q@qq.com>
Thu, 12 Aug 2021 17:32:44 +0000 (01:32 +0800)
committerGitHub <noreply@github.com>
Thu, 12 Aug 2021 17:32:44 +0000 (01:32 +0800)
14 files changed:
adjust.go
adjust_test.go
calc.go
cell.go
col.go
lib.go
merge.go
merge_test.go
picture.go
pivotTable.go
rows.go
sheet.go
xmlSharedStrings.go
xmlWorksheet.go

index 1fe6663..9f2176f 100644 (file)
--- a/adjust.go
+++ b/adjust.go
@@ -145,7 +145,7 @@ func (f *File) adjustAutoFilter(ws *xlsxWorksheet, dir adjustDirection, num, off
                return nil
        }
 
-       coordinates, err := f.areaRefToCoordinates(ws.AutoFilter.Ref)
+       coordinates, err := areaRefToCoordinates(ws.AutoFilter.Ref)
        if err != nil {
                return err
        }
@@ -199,7 +199,7 @@ func (f *File) adjustMergeCells(ws *xlsxWorksheet, dir adjustDirection, num, off
 
        for i := 0; i < len(ws.MergeCells.Cells); i++ {
                areaData := ws.MergeCells.Cells[i]
-               coordinates, err := f.areaRefToCoordinates(areaData.Ref)
+               coordinates, err := areaRefToCoordinates(areaData.Ref)
                if err != nil {
                        return err
                }
@@ -219,7 +219,7 @@ func (f *File) adjustMergeCells(ws *xlsxWorksheet, dir adjustDirection, num, off
                        x1 = f.adjustMergeCellsHelper(x1, num, offset)
                        x2 = f.adjustMergeCellsHelper(x2, num, offset)
                }
-               if x1 == x2 && y1 == y2 {
+               if x1 == x2 && y1 == y2 && i >= 0 {
                        f.deleteMergeCell(ws, i)
                        i--
                }
@@ -234,7 +234,7 @@ func (f *File) adjustMergeCells(ws *xlsxWorksheet, dir adjustDirection, num, off
 // compare and calculate cell axis by the given pivot, operation axis and
 // offset.
 func (f *File) adjustMergeCellsHelper(pivot, num, offset int) int {
-       if pivot >= num {
+       if pivot > num {
                pivot += offset
                if pivot < 1 {
                        return 1
index ced091d..f56f763 100644 (file)
@@ -84,6 +84,10 @@ func TestAdjustHelper(t *testing.T) {
        assert.EqualError(t, f.adjustHelper("SheetN", rows, 0, 0), "sheet SheetN is not exist")
 }
 
+func TestAdjustMergeCellsHelper(t *testing.T) {
+       assert.Equal(t, 1, NewFile().adjustMergeCellsHelper(1, 0, -2))
+}
+
 func TestAdjustCalcChain(t *testing.T) {
        f := NewFile()
        f.CalcChain = &xlsxCalcChain{
diff --git a/calc.go b/calc.go
index cd7fa97..a03520b 100644 (file)
--- a/calc.go
+++ b/calc.go
@@ -5103,11 +5103,11 @@ func (fn *formulaFuncs) kth(name string, argsList *list.List) formulaArg {
                return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 2 arguments", name))
        }
        array := argsList.Front().Value.(formulaArg).ToList()
-       kArg := argsList.Back().Value.(formulaArg).ToNumber()
-       if kArg.Type != ArgNumber {
-               return kArg
+       argK := argsList.Back().Value.(formulaArg).ToNumber()
+       if argK.Type != ArgNumber {
+               return argK
        }
-       k := int(kArg.Number)
+       k := int(argK.Number)
        if k < 1 {
                return newErrorFormulaArg(formulaErrorNUM, "k should be > 0")
        }
@@ -7177,7 +7177,7 @@ func (fn *formulaFuncs) VLOOKUP(argsList *list.List) formulaArg {
 func vlookupBinarySearch(tableArray, lookupValue formulaArg) (matchIdx int, wasExact bool) {
        var low, high, lastMatchIdx int = 0, len(tableArray.Matrix) - 1, -1
        for low <= high {
-               var mid int = low + (high-low)/2
+               mid := low + (high-low)/2
                mtx := tableArray.Matrix[mid]
                lhs := mtx[0]
                switch lookupValue.Type {
@@ -7216,7 +7216,7 @@ func vlookupBinarySearch(tableArray, lookupValue formulaArg) (matchIdx int, wasE
 func hlookupBinarySearch(row []formulaArg, lookupValue formulaArg) (matchIdx int, wasExact bool) {
        var low, high, lastMatchIdx int = 0, len(row) - 1, -1
        for low <= high {
-               var mid int = low + (high-low)/2
+               mid := low + (high-low)/2
                mtx := row[mid]
                result := compareFormulaArg(mtx, lookupValue, false, false)
                if result == criteriaEq {
diff --git a/cell.go b/cell.go
index 9200d13..6ad5f44 100644 (file)
--- a/cell.go
+++ b/cell.go
@@ -101,6 +101,28 @@ func (f *File) SetCellValue(sheet, axis string, value interface{}) error {
        return err
 }
 
+// String extracts characters from a string item.
+func (x xlsxSI) String() string {
+       if len(x.R) > 0 {
+               var rows strings.Builder
+               for _, s := range x.R {
+                       if s.T != nil {
+                               rows.WriteString(s.T.Val)
+                       }
+               }
+               return bstrUnmarshal(rows.String())
+       }
+       if x.T != nil {
+               return bstrUnmarshal(x.T.Val)
+       }
+       return ""
+}
+
+// hasValue determine if cell non-blank value.
+func (c *xlsxC) hasValue() bool {
+       return c.S != 0 || c.V != "" || c.F != nil || c.T != ""
+}
+
 // setCellIntFunc is a wrapper of SetCellInt.
 func (f *File) setCellIntFunc(sheet, axis string, value interface{}) error {
        var err error
@@ -431,13 +453,11 @@ func (f *File) GetCellHyperLink(sheet, axis string) (bool, string, error) {
        if _, _, err := SplitCellName(axis); err != nil {
                return false, "", err
        }
-
        ws, err := f.workSheetReader(sheet)
        if err != nil {
                return false, "", err
        }
-       axis, err = f.mergeCellsParser(ws, axis)
-       if err != nil {
+       if axis, err = f.mergeCellsParser(ws, axis); err != nil {
                return false, "", err
        }
        if ws.Hyperlinks != nil {
@@ -485,8 +505,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
        if err != nil {
                return err
        }
-       axis, err = f.mergeCellsParser(ws, axis)
-       if err != nil {
+       if axis, err = f.mergeCellsParser(ws, axis); err != nil {
                return err
        }
 
@@ -932,7 +951,7 @@ func (f *File) checkCellInArea(cell, area string) (bool, error) {
        if len(rng) != 2 {
                return false, err
        }
-       coordinates, err := f.areaRefToCoordinates(area)
+       coordinates, err := areaRefToCoordinates(area)
        if err != nil {
                return false, err
        }
diff --git a/col.go b/col.go
index 088fac9..7fbeeba 100644 (file)
--- a/col.go
+++ b/col.go
@@ -616,10 +616,10 @@ func (f *File) positionObjectPixels(sheet string, col, row, x1, y1, width, heigh
 // getColWidth provides a function to get column width in pixels by given
 // sheet name and column number.
 func (f *File) getColWidth(sheet string, col int) int {
-       xlsx, _ := f.workSheetReader(sheet)
-       if xlsx.Cols != nil {
+       ws, _ := f.workSheetReader(sheet)
+       if ws.Cols != nil {
                var width float64
-               for _, v := range xlsx.Cols.Col {
+               for _, v := range ws.Cols.Col {
                        if v.Min <= col && col <= v.Max {
                                width = v.Width
                        }
diff --git a/lib.go b/lib.go
index 7db14c4..912f738 100644 (file)
--- a/lib.go
+++ b/lib.go
@@ -221,12 +221,11 @@ func CoordinatesToCellName(col, row int, abs ...bool) (string, error) {
 
 // areaRefToCoordinates provides a function to convert area reference to a
 // pair of coordinates.
-func (f *File) areaRefToCoordinates(ref string) ([]int, error) {
+func areaRefToCoordinates(ref string) ([]int, error) {
        rng := strings.Split(strings.Replace(ref, "$", "", -1), ":")
        if len(rng) < 2 {
                return nil, ErrParameterInvalid
        }
-
        return areaRangeToCoordinates(rng[0], rng[1])
 }
 
@@ -290,7 +289,7 @@ func (f *File) flatSqref(sqref string) (cells map[int][][]int, err error) {
                        }
                        cells[col] = append(cells[col], []int{col, row})
                case 2:
-                       if coordinates, err = f.areaRefToCoordinates(ref); err != nil {
+                       if coordinates, err = areaRefToCoordinates(ref); err != nil {
                                return
                        }
                        _ = sortCoordinates(coordinates)
index 7769b89..1cd8acd 100644 (file)
--- a/merge.go
+++ b/merge.go
 
 package excelize
 
-import (
-       "fmt"
-       "strings"
-)
+import "strings"
+
+// Rect gets merged cell rectangle coordinates sequence.
+func (mc *xlsxMergeCell) Rect() ([]int, error) {
+       var err error
+       if mc.rect == nil {
+               mc.rect, err = areaRefToCoordinates(mc.Ref)
+       }
+       return mc.rect, err
+}
 
 // MergeCell provides a function to merge cells by given coordinate area and
 // sheet name. Merging cells only keeps the upper-left cell value, and
@@ -24,7 +30,9 @@ import (
 //    err := f.MergeCell("Sheet1", "D3", "E9")
 //
 // If you create a merged cell that overlaps with another existing merged cell,
-// those merged cells that already exist will be removed.
+// those merged cells that already exist will be removed. The cell coordinates
+// tuple after merging in the following range will be: A1(x3,y1) D1(x2,y1)
+// A8(x3,y4) D8(x2,y4)
 //
 //                 B1(x1,y1)      D1(x2,y1)
 //               +------------------------+
@@ -39,15 +47,15 @@ import (
 //    +------------------------+
 //
 func (f *File) MergeCell(sheet, hcell, vcell string) error {
-       rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
+       rect, err := areaRefToCoordinates(hcell + ":" + vcell)
        if err != nil {
                return err
        }
        // Correct the coordinate area, such correct C1:B3 to B1:C3.
-       _ = sortCoordinates(rect1)
+       _ = sortCoordinates(rect)
 
-       hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
-       vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
+       hcell, _ = CoordinatesToCellName(rect[0], rect[1])
+       vcell, _ = CoordinatesToCellName(rect[2], rect[3])
 
        ws, err := f.workSheetReader(sheet)
        if err != nil {
@@ -55,49 +63,9 @@ func (f *File) MergeCell(sheet, hcell, vcell string) error {
        }
        ref := hcell + ":" + vcell
        if ws.MergeCells != nil {
-               for i := 0; i < len(ws.MergeCells.Cells); i++ {
-                       cellData := ws.MergeCells.Cells[i]
-                       if cellData == nil {
-                               continue
-                       }
-                       cc := strings.Split(cellData.Ref, ":")
-                       if len(cc) != 2 {
-                               return fmt.Errorf("invalid area %q", cellData.Ref)
-                       }
-
-                       rect2, err := f.areaRefToCoordinates(cellData.Ref)
-                       if err != nil {
-                               return err
-                       }
-
-                       // Delete the merged cells of the overlapping area.
-                       if isOverlap(rect1, rect2) {
-                               ws.MergeCells.Cells = append(ws.MergeCells.Cells[:i], ws.MergeCells.Cells[i+1:]...)
-                               i--
-
-                               if rect1[0] > rect2[0] {
-                                       rect1[0], rect2[0] = rect2[0], rect1[0]
-                               }
-
-                               if rect1[2] < rect2[2] {
-                                       rect1[2], rect2[2] = rect2[2], rect1[2]
-                               }
-
-                               if rect1[1] > rect2[1] {
-                                       rect1[1], rect2[1] = rect2[1], rect1[1]
-                               }
-
-                               if rect1[3] < rect2[3] {
-                                       rect1[3], rect2[3] = rect2[3], rect1[3]
-                               }
-                               hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
-                               vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
-                               ref = hcell + ":" + vcell
-                       }
-               }
-               ws.MergeCells.Cells = append(ws.MergeCells.Cells, &xlsxMergeCell{Ref: ref})
+               ws.MergeCells.Cells = append(ws.MergeCells.Cells, &xlsxMergeCell{Ref: ref, rect: rect})
        } else {
-               ws.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref}}}
+               ws.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref, rect: rect}}}
        }
        ws.MergeCells.Count = len(ws.MergeCells.Cells)
        return err
@@ -114,7 +82,7 @@ func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
        if err != nil {
                return err
        }
-       rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
+       rect1, err := areaRefToCoordinates(hcell + ":" + vcell)
        if err != nil {
                return err
        }
@@ -126,26 +94,19 @@ func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
        if ws.MergeCells == nil {
                return nil
        }
-
+       if err = f.mergeOverlapCells(ws); err != nil {
+               return err
+       }
        i := 0
-       for _, cellData := range ws.MergeCells.Cells {
-               if cellData == nil {
+       for _, mergeCell := range ws.MergeCells.Cells {
+               if mergeCell == nil {
                        continue
                }
-               cc := strings.Split(cellData.Ref, ":")
-               if len(cc) != 2 {
-                       return fmt.Errorf("invalid area %q", cellData.Ref)
-               }
-
-               rect2, err := f.areaRefToCoordinates(cellData.Ref)
-               if err != nil {
-                       return err
-               }
-
+               rect2, _ := areaRefToCoordinates(mergeCell.Ref)
                if isOverlap(rect1, rect2) {
                        continue
                }
-               ws.MergeCells.Cells[i] = cellData
+               ws.MergeCells.Cells[i] = mergeCell
                i++
        }
        ws.MergeCells.Cells = ws.MergeCells.Cells[:i]
@@ -165,8 +126,10 @@ func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
                return mergeCells, err
        }
        if ws.MergeCells != nil {
+               if err = f.mergeOverlapCells(ws); err != nil {
+                       return mergeCells, err
+               }
                mergeCells = make([]MergeCell, 0, len(ws.MergeCells.Cells))
-
                for i := range ws.MergeCells.Cells {
                        ref := ws.MergeCells.Cells[i].Ref
                        axis := strings.Split(ref, ":")[0]
@@ -174,10 +137,128 @@ func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
                        mergeCells = append(mergeCells, []string{ref, val})
                }
        }
-
        return mergeCells, err
 }
 
+// overlapRange calculate overlap range of merged cells, and returns max
+// column and rows of the range.
+func overlapRange(ws *xlsxWorksheet) (row, col int, err error) {
+       var rect []int
+       for _, mergeCell := range ws.MergeCells.Cells {
+               if mergeCell == nil {
+                       continue
+               }
+               if rect, err = mergeCell.Rect(); err != nil {
+                       return
+               }
+               x1, y1, x2, y2 := rect[0], rect[1], rect[2], rect[3]
+               if x1 > col {
+                       col = x1
+               }
+               if x2 > col {
+                       col = x2
+               }
+               if y1 > row {
+                       row = y1
+               }
+               if y2 > row {
+                       row = y2
+               }
+       }
+       return
+}
+
+// flatMergedCells convert merged cells range reference to cell-matrix.
+func flatMergedCells(ws *xlsxWorksheet, matrix [][]*xlsxMergeCell) error {
+       for i, cell := range ws.MergeCells.Cells {
+               rect, err := cell.Rect()
+               if err != nil {
+                       return err
+               }
+               x1, y1, x2, y2 := rect[0]-1, rect[1]-1, rect[2]-1, rect[3]-1
+               var overlapCells []*xlsxMergeCell
+               for x := x1; x <= x2; x++ {
+                       for y := y1; y <= y2; y++ {
+                               if matrix[x][y] != nil {
+                                       overlapCells = append(overlapCells, matrix[x][y])
+                               }
+                               matrix[x][y] = cell
+                       }
+               }
+               if len(overlapCells) != 0 {
+                       newCell := cell
+                       for _, overlapCell := range overlapCells {
+                               newCell = mergeCell(cell, overlapCell)
+                       }
+                       newRect, _ := newCell.Rect()
+                       x1, y1, x2, y2 := newRect[0]-1, newRect[1]-1, newRect[2]-1, newRect[3]-1
+                       for x := x1; x <= x2; x++ {
+                               for y := y1; y <= y2; y++ {
+                                       matrix[x][y] = newCell
+                               }
+                       }
+                       ws.MergeCells.Cells[i] = newCell
+               }
+       }
+       return nil
+}
+
+// mergeOverlapCells merge overlap cells.
+func (f *File) mergeOverlapCells(ws *xlsxWorksheet) error {
+       rows, cols, err := overlapRange(ws)
+       if err != nil {
+               return err
+       }
+       if rows == 0 || cols == 0 {
+               return nil
+       }
+       matrix := make([][]*xlsxMergeCell, cols)
+       for i := range matrix {
+               matrix[i] = make([]*xlsxMergeCell, rows)
+       }
+       _ = flatMergedCells(ws, matrix)
+       mergeCells := ws.MergeCells.Cells[:0]
+       for _, cell := range ws.MergeCells.Cells {
+               rect, _ := cell.Rect()
+               x1, y1, x2, y2 := rect[0]-1, rect[1]-1, rect[2]-1, rect[3]-1
+               if matrix[x1][y1] == cell {
+                       mergeCells = append(mergeCells, cell)
+                       for x := x1; x <= x2; x++ {
+                               for y := y1; y <= y2; y++ {
+                                       matrix[x][y] = nil
+                               }
+                       }
+               }
+       }
+       ws.MergeCells.Count, ws.MergeCells.Cells = len(mergeCells), mergeCells
+       return nil
+}
+
+// mergeCell merge two cells.
+func mergeCell(cell1, cell2 *xlsxMergeCell) *xlsxMergeCell {
+       rect1, _ := cell1.Rect()
+       rect2, _ := cell2.Rect()
+
+       if rect1[0] > rect2[0] {
+               rect1[0], rect2[0] = rect2[0], rect1[0]
+       }
+
+       if rect1[2] < rect2[2] {
+               rect1[2], rect2[2] = rect2[2], rect1[2]
+       }
+
+       if rect1[1] > rect2[1] {
+               rect1[1], rect2[1] = rect2[1], rect1[1]
+       }
+
+       if rect1[3] < rect2[3] {
+               rect1[3], rect2[3] = rect2[3], rect1[3]
+       }
+       hcell, _ := CoordinatesToCellName(rect1[0], rect1[1])
+       vcell, _ := CoordinatesToCellName(rect1[2], rect1[3])
+       return &xlsxMergeCell{rect: rect1, Ref: hcell + ":" + vcell}
+}
+
 // MergeCell define a merged cell data.
 // It consists of the following structure.
 // example: []string{"D4:E10", "cell value"}
index 41c122c..a370126 100644 (file)
@@ -27,7 +27,7 @@ func TestMergeCell(t *testing.T) {
        assert.NoError(t, f.SetCellHyperLink("Sheet1", "J11", "https://github.com/xuri/excelize", "External"))
        assert.NoError(t, f.SetCellFormula("Sheet1", "G12", "SUM(Sheet1!B19,Sheet1!C19)"))
        value, err := f.GetCellValue("Sheet1", "H11")
-       assert.Equal(t, "0.5", value)
+       assert.Equal(t, "100", value)
        assert.NoError(t, err)
        value, err = f.GetCellValue("Sheet2", "A6") // Merged cell ref is single coordinate.
        assert.Equal(t, "", value)
@@ -75,16 +75,24 @@ func TestMergeCell(t *testing.T) {
        assert.True(t, ok)
        ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{nil, nil}}
        assert.NoError(t, f.MergeCell("Sheet1", "A2", "B3"))
+}
 
-       ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
-       assert.True(t, ok)
-       ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A1"}}}
-       assert.EqualError(t, f.MergeCell("Sheet1", "A2", "B3"), `invalid area "A1"`)
+func TestMergeCellOverlap(t *testing.T) {
+       f := NewFile()
+       assert.NoError(t, f.MergeCell("Sheet1", "A1", "C2"))
+       assert.NoError(t, f.MergeCell("Sheet1", "B2", "D3"))
+       assert.NoError(t, f.SaveAs(filepath.Join("test", "TestMergeCellOverlap.xlsx")))
 
-       ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
-       assert.True(t, ok)
-       ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A:A"}}}
-       assert.EqualError(t, f.MergeCell("Sheet1", "A2", "B3"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+       f, err := OpenFile(filepath.Join("test", "TestMergeCellOverlap.xlsx"))
+       if !assert.NoError(t, err) {
+               t.FailNow()
+       }
+       mc, err := f.GetMergeCells("Sheet1")
+       assert.NoError(t, err)
+       assert.Equal(t, 1, len(mc))
+       assert.Equal(t, "A1", mc[0].GetStartAxis())
+       assert.Equal(t, "D3", mc[0].GetEndAxis())
+       assert.Equal(t, "", mc[0].GetCellValue())
 }
 
 func TestGetMergeCells(t *testing.T) {
@@ -173,11 +181,15 @@ func TestUnmergeCell(t *testing.T) {
        ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
        assert.True(t, ok)
        ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A1"}}}
-       assert.EqualError(t, f.UnmergeCell("Sheet1", "A2", "B3"), `invalid area "A1"`)
+       assert.EqualError(t, f.UnmergeCell("Sheet1", "A2", "B3"), "parameter is invalid")
 
        ws, ok = f.Sheet.Load("xl/worksheets/sheet1.xml")
        assert.True(t, ok)
        ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A:A"}}}
        assert.EqualError(t, f.UnmergeCell("Sheet1", "A2", "B3"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+}
 
+func TestFlatMergedCells(t *testing.T) {
+       ws := &xlsxWorksheet{MergeCells: &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A1"}}}}
+       assert.EqualError(t, flatMergedCells(ws, [][]*xlsxMergeCell{}), "parameter is invalid")
 }
index d22a708..c37899e 100644 (file)
@@ -148,6 +148,7 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
        if err != nil {
                return err
        }
+       ws.Lock()
        // Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
        drawingID := f.countDrawings() + 1
        drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
@@ -162,6 +163,7 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
                }
                drawingHyperlinkRID = f.addRels(drawingRels, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType)
        }
+       ws.Unlock()
        err = f.addDrawingPicture(sheet, drawingXML, cell, name, img.Width, img.Height, drawingRID, drawingHyperlinkRID, formatSet)
        if err != nil {
                return err
index 07cf84c..0b0e5af 100644 (file)
@@ -198,7 +198,7 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
                return "", []int{}, ErrParameterInvalid
        }
        trimRng := strings.Replace(rng[1], "$", "", -1)
-       coordinates, err := f.areaRefToCoordinates(trimRng)
+       coordinates, err := areaRefToCoordinates(trimRng)
        if err != nil {
                return rng[0], []int{}, err
        }
diff --git a/rows.go b/rows.go
index fcd3c1a..5fa2cb4 100644 (file)
--- a/rows.go
+++ b/rows.go
@@ -614,7 +614,7 @@ func (f *File) duplicateMergeCells(sheet string, ws *xlsxWorksheet, row, row2 in
                row++
        }
        for _, rng := range ws.MergeCells.Cells {
-               coordinates, err := f.areaRefToCoordinates(rng.Ref)
+               coordinates, err := areaRefToCoordinates(rng.Ref)
                if err != nil {
                        return err
                }
@@ -624,7 +624,7 @@ func (f *File) duplicateMergeCells(sheet string, ws *xlsxWorksheet, row, row2 in
        }
        for i := 0; i < len(ws.MergeCells.Cells); i++ {
                areaData := ws.MergeCells.Cells[i]
-               coordinates, _ := f.areaRefToCoordinates(areaData.Ref)
+               coordinates, _ := areaRefToCoordinates(areaData.Ref)
                x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
                if y1 == y2 && y1 == row {
                        from, _ := CoordinatesToCellName(x1, row2)
index 756eb81..1c4b355 100644 (file)
--- a/sheet.go
+++ b/sheet.go
@@ -158,6 +158,9 @@ func (f *File) workSheetWriter() {
        f.Sheet.Range(func(p, ws interface{}) bool {
                if ws != nil {
                        sheet := ws.(*xlsxWorksheet)
+                       if sheet.MergeCells != nil && len(sheet.MergeCells.Cells) > 0 {
+                               _ = f.mergeOverlapCells(sheet)
+                       }
                        for k, v := range sheet.SheetData.Row {
                                sheet.SheetData.Row[k].C = trimCell(v.C)
                        }
index 816c931..e505d26 100644 (file)
 
 package excelize
 
-import (
-       "encoding/xml"
-       "strings"
-)
+import "encoding/xml"
 
 // xlsxSST directly maps the sst element from the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main. String values may
@@ -44,23 +41,6 @@ type xlsxSI struct {
        PhoneticPr *xlsxPhoneticPr    `xml:"phoneticPr"`
 }
 
-// String extracts characters from a string item.
-func (x xlsxSI) String() string {
-       if len(x.R) > 0 {
-               var rows strings.Builder
-               for _, s := range x.R {
-                       if s.T != nil {
-                               rows.WriteString(s.T.Val)
-                       }
-               }
-               return bstrUnmarshal(rows.String())
-       }
-       if x.T != nil {
-               return bstrUnmarshal(x.T.Val)
-       }
-       return ""
-}
-
 // xlsxR represents a run of rich text. A rich text run is a region of text
 // that share a common set of properties, such as formatting properties. The
 // properties are defined in the rPr element, and the text displayed to the
index 4499546..697504e 100644 (file)
@@ -399,7 +399,8 @@ type xlsxCustomSheetView struct {
 
 // xlsxMergeCell directly maps the mergeCell element. A single merged cell.
 type xlsxMergeCell struct {
-       Ref string `xml:"ref,attr,omitempty"`
+       Ref  string `xml:"ref,attr,omitempty"`
+       rect []int
 }
 
 // xlsxMergeCells directly maps the mergeCells element. This collection
@@ -468,10 +469,6 @@ type xlsxC struct {
        IS *xlsxSI `xml:"is"`
 }
 
-func (c *xlsxC) hasValue() bool {
-       return c.S != 0 || c.V != "" || c.F != nil || c.T != ""
-}
-
 // xlsxF represents a formula for the cell. The formula expression is
 // contained in the character node of this element.
 type xlsxF struct {