Skip to content

Commit eb0d8a5

Browse files
Neuglscrush-wu
authored andcommitted
Optimize the GetSheetDimension function by parse worksheet XML in stream mode (#2188)
1 parent e1d4da6 commit eb0d8a5

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

sheet.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,12 +2122,44 @@ func (f *File) SetSheetDimension(sheet, rangeRef string) error {
21222122
// GetSheetDimension provides the method to get the used range of the worksheet.
21232123
func (f *File) GetSheetDimension(sheet string) (string, error) {
21242124
var ref string
2125-
ws, err := f.workSheetReader(sheet)
2126-
if err != nil {
2125+
if err := checkSheetName(sheet); err != nil {
21272126
return ref, err
21282127
}
2129-
if ws.Dimension != nil {
2130-
ref = ws.Dimension.Ref
2128+
name, ok := f.getSheetXMLPath(sheet)
2129+
if !ok {
2130+
return ref, ErrSheetNotExist{sheet}
2131+
}
2132+
if worksheet, ok := f.Sheet.Load(name); ok && worksheet != nil {
2133+
ws := worksheet.(*xlsxWorksheet)
2134+
if ws.Dimension != nil {
2135+
ref = ws.Dimension.Ref
2136+
}
2137+
return ref, nil
2138+
}
2139+
needClose, decoder, tempFile, err := f.xmlDecoder(name)
2140+
if needClose && err == nil {
2141+
defer func() {
2142+
err = tempFile.Close()
2143+
}()
2144+
}
2145+
for {
2146+
token, _ := decoder.Token()
2147+
if token == nil {
2148+
break
2149+
}
2150+
switch xmlElement := token.(type) {
2151+
case xml.StartElement:
2152+
if xmlElement.Name.Local == "dimension" {
2153+
for _, attr := range xmlElement.Attr {
2154+
if attr.Name.Local == "ref" {
2155+
return attr.Value, err
2156+
}
2157+
}
2158+
}
2159+
if xmlElement.Name.Local == "sheetData" {
2160+
return ref, err
2161+
}
2162+
}
21312163
}
21322164
return ref, err
21332165
}

sheet_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,36 @@ func TestSheetDimension(t *testing.T) {
826826
dimension, err = f.GetSheetDimension("SheetN")
827827
assert.Empty(t, dimension)
828828
assert.EqualError(t, err, "sheet SheetN does not exist")
829+
830+
// Test get the worksheet dimension with blank worksheet name
831+
dimension, err = f.GetSheetDimension("")
832+
assert.Empty(t, dimension)
833+
assert.Equal(t, err, ErrSheetNameBlank)
834+
835+
// Test get the worksheet dimension with in mode
836+
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipXMLSizeLimit: 128})
837+
assert.NoError(t, err)
838+
dimension, err = f.GetSheetDimension("Sheet1")
839+
assert.Equal(t, "A19:D22", dimension)
840+
assert.NoError(t, err)
841+
assert.NoError(t, f.Close())
842+
843+
// Test get the worksheet dimension in stream mode without dimension element
844+
f, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipXMLSizeLimit: 128})
845+
assert.NoError(t, err)
846+
tempFile, ok := f.tempFiles.Load("xl/worksheets/sheet1.xml")
847+
assert.True(t, ok)
848+
assert.NoError(t, os.WriteFile(tempFile.(string), fmt.Appendf(nil, `<worksheet xmlns="%s"><sheetData/></worksheet>`, NameSpaceSpreadSheet.Value), 0o644))
849+
dimension, err = f.GetSheetDimension("Sheet1")
850+
assert.NoError(t, err)
851+
assert.Empty(t, dimension)
852+
853+
// Test get the worksheet dimension in stream mode without sheetData element
854+
assert.NoError(t, os.WriteFile(tempFile.(string), fmt.Appendf(nil, `<worksheet xmlns="%s"></worksheet>`, NameSpaceSpreadSheet.Value), 0o644))
855+
dimension, err = f.GetSheetDimension("Sheet1")
856+
assert.NoError(t, err)
857+
assert.Empty(t, dimension)
858+
assert.NoError(t, f.Close())
829859
}
830860

831861
func TestAddIgnoredErrors(t *testing.T) {

0 commit comments

Comments
 (0)