Support get rich data value rels index from rich value part (#1866)
This commit is contained in:
parent
5e500f5e5d
commit
ffad7aecb5
11
excelize.go
11
excelize.go
|
@ -601,6 +601,17 @@ func (f *File) metadataReader() (*xlsxMetadata, error) {
|
||||||
return &mataData, nil
|
return &mataData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// richValueReader provides a function to get the pointer to the structure after
|
||||||
|
// deserialization of xl/richData/richvalue.xml.
|
||||||
|
func (f *File) richValueReader() (*xlsxRichValueData, error) {
|
||||||
|
var richValue xlsxRichValueData
|
||||||
|
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValue)))).
|
||||||
|
Decode(&richValue); err != nil && err != io.EOF {
|
||||||
|
return &richValue, err
|
||||||
|
}
|
||||||
|
return &richValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
// richValueRelReader provides a function to get the pointer to the structure
|
// richValueRelReader provides a function to get the pointer to the structure
|
||||||
// after deserialization of xl/richData/richValueRel.xml.
|
// after deserialization of xl/richData/richValueRel.xml.
|
||||||
func (f *File) richValueRelReader() (*xlsxRichValueRels, error) {
|
func (f *File) richValueRelReader() (*xlsxRichValueRels, error) {
|
||||||
|
|
42
picture.go
42
picture.go
|
@ -450,7 +450,8 @@ func (f *File) addMedia(file []byte, ext string) string {
|
||||||
// GetPictures provides a function to get picture meta info and raw content
|
// GetPictures provides a function to get picture meta info and raw content
|
||||||
// embed in spreadsheet by given worksheet and cell name. This function
|
// embed in spreadsheet by given worksheet and cell name. This function
|
||||||
// returns the image contents as []byte data types. This function is
|
// returns the image contents as []byte data types. This function is
|
||||||
// concurrency safe. For example:
|
// concurrency safe. Note that, this function doesn't support getting cell image
|
||||||
|
// inserted by IMAGE formula function currently. For example:
|
||||||
//
|
//
|
||||||
// f, err := excelize.OpenFile("Book1.xlsx")
|
// f, err := excelize.OpenFile("Book1.xlsx")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
|
@ -506,7 +507,8 @@ func (f *File) GetPictures(sheet, cell string) ([]Picture, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPictureCells returns all picture cell references in a worksheet by a
|
// GetPictureCells returns all picture cell references in a worksheet by a
|
||||||
// specific worksheet name.
|
// specific worksheet name. Note that, this function doesn't support getting
|
||||||
|
// cell image inserted by IMAGE formula function currently.
|
||||||
func (f *File) GetPictureCells(sheet string) ([]string, error) {
|
func (f *File) GetPictureCells(sheet string) ([]string, error) {
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
ws, err := f.workSheetReader(sheet)
|
ws, err := f.workSheetReader(sheet)
|
||||||
|
@ -790,7 +792,7 @@ func (f *File) cellImagesReader() (*decodeCellImages, error) {
|
||||||
return f.DecodeCellImages, nil
|
return f.DecodeCellImages, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getImageCells returns all the Microsoft 365 cell images and the Kingsoft WPS
|
// getImageCells returns all the cell images and the Kingsoft WPS
|
||||||
// Office embedded image cells reference by given worksheet name.
|
// Office embedded image cells reference by given worksheet name.
|
||||||
func (f *File) getImageCells(sheet string) ([]string, error) {
|
func (f *File) getImageCells(sheet string) ([]string, error) {
|
||||||
var (
|
var (
|
||||||
|
@ -823,7 +825,29 @@ func (f *File) getImageCells(sheet string) ([]string, error) {
|
||||||
return cells, err
|
return cells, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getImageCellRel returns the Microsoft 365 cell image relationship.
|
// getImageCellRichValueIdx returns index of the cell image rich value by given
|
||||||
|
// cell value meta index and meta blocks.
|
||||||
|
func (f *File) getImageCellRichValueIdx(vm uint, blocks *xlsxMetadataBlocks) (int, error) {
|
||||||
|
richValueIdx := blocks.Bk[vm-1].Rc[0].V
|
||||||
|
richValue, err := f.richValueReader()
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
if richValueIdx >= len(richValue.Rv) {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
rv := richValue.Rv[richValueIdx].V
|
||||||
|
if len(rv) != 2 || rv[1] != "5" {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
richValueRelIdx, err := strconv.Atoi(rv[0])
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
return richValueRelIdx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// getImageCellRel returns the cell image relationship.
|
||||||
func (f *File) getImageCellRel(c *xlsxC) (*xlsxRelationship, error) {
|
func (f *File) getImageCellRel(c *xlsxC) (*xlsxRelationship, error) {
|
||||||
var r *xlsxRelationship
|
var r *xlsxRelationship
|
||||||
if c.Vm == nil || c.V != formulaErrorVALUE {
|
if c.Vm == nil || c.V != formulaErrorVALUE {
|
||||||
|
@ -837,21 +861,25 @@ func (f *File) getImageCellRel(c *xlsxC) (*xlsxRelationship, error) {
|
||||||
if vmd == nil || int(*c.Vm) > len(vmd.Bk) || len(vmd.Bk[*c.Vm-1].Rc) == 0 {
|
if vmd == nil || int(*c.Vm) > len(vmd.Bk) || len(vmd.Bk[*c.Vm-1].Rc) == 0 {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
richValueRelIdx, err := f.getImageCellRichValueIdx(*c.Vm, vmd)
|
||||||
|
if err != nil || richValueRelIdx == -1 {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
richValueRel, err := f.richValueRelReader()
|
richValueRel, err := f.richValueRelReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
if vmd.Bk[*c.Vm-1].Rc[0].V >= len(richValueRel.Rels) {
|
if richValueRelIdx >= len(richValueRel.Rels) {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
rID := richValueRel.Rels[vmd.Bk[*c.Vm-1].Rc[0].V].ID
|
rID := richValueRel.Rels[richValueRelIdx].ID
|
||||||
if r = f.getRichDataRichValueRelRelationships(rID); r != nil && r.Type != SourceRelationshipImage {
|
if r = f.getRichDataRichValueRelRelationships(rID); r != nil && r.Type != SourceRelationshipImage {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCellImages provides a function to get the Microsoft 365 cell images and
|
// getCellImages provides a function to get the cell images and
|
||||||
// the Kingsoft WPS Office embedded cell images by given worksheet name and cell
|
// the Kingsoft WPS Office embedded cell images by given worksheet name and cell
|
||||||
// reference.
|
// reference.
|
||||||
func (f *File) getCellImages(sheet, cell string) ([]Picture, error) {
|
func (f *File) getCellImages(sheet, cell string) ([]Picture, error) {
|
||||||
|
|
|
@ -452,17 +452,22 @@ func TestGetCellImages(t *testing.T) {
|
||||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
assert.NoError(t, f.Close())
|
assert.NoError(t, f.Close())
|
||||||
|
|
||||||
// Test get the Microsoft 365 cell images
|
// Test get the cell images
|
||||||
f = NewFile()
|
prepareWorkbook := func() *File {
|
||||||
assert.NoError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.png"), nil))
|
f := NewFile()
|
||||||
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata count="1"><bk><rc t="1" v="0"/></bk></valueMetadata></metadata>`))
|
assert.NoError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.png"), nil))
|
||||||
f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(`<richValueRels><rel r:id="rId1"/></richValueRels>`))
|
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata count="1"><bk><rc t="1" v="0"/></bk></valueMetadata></metadata>`))
|
||||||
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="%s" Target="../media/image1.png"/></Relationships>`, SourceRelationshipImage)))
|
f.Pkg.Store(defaultXMLRichDataRichValue, []byte(`<rvData count="1"><rv s="0"><v>0</v><v>5</v></rv></rvData>`))
|
||||||
f.Sheet.Store("xl/worksheets/sheet1.xml", &xlsxWorksheet{
|
f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(`<richValueRels><rel r:id="rId1"/></richValueRels>`))
|
||||||
SheetData: xlsxSheetData{Row: []xlsxRow{
|
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="%s" Target="../media/image1.png"/></Relationships>`, SourceRelationshipImage)))
|
||||||
{R: 1, C: []xlsxC{{R: "A1", T: "e", V: formulaErrorVALUE, Vm: uintPtr(1)}}},
|
f.Sheet.Store("xl/worksheets/sheet1.xml", &xlsxWorksheet{
|
||||||
}},
|
SheetData: xlsxSheetData{Row: []xlsxRow{
|
||||||
})
|
{R: 1, C: []xlsxC{{R: "A1", T: "e", V: formulaErrorVALUE, Vm: uintPtr(1)}}},
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
f = prepareWorkbook()
|
||||||
pics, err := f.GetPictures("Sheet1", "A1")
|
pics, err := f.GetPictures("Sheet1", "A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, len(pics))
|
assert.Equal(t, 1, len(pics))
|
||||||
|
@ -471,41 +476,64 @@ func TestGetCellImages(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []string{"A1"}, cells)
|
assert.Equal(t, []string{"A1"}, cells)
|
||||||
|
|
||||||
// Test get the Microsoft 365 cell images without image relationships parts
|
// Test get the cell images without image relationships parts
|
||||||
f.Relationships.Delete(defaultXMLRichDataRichValueRelRels)
|
f.Relationships.Delete(defaultXMLRichDataRichValueRelRels)
|
||||||
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="%s" Target="../media/image1.png"/></Relationships>`, SourceRelationshipHyperLink)))
|
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, []byte(fmt.Sprintf(`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="%s" Target="../media/image1.png"/></Relationships>`, SourceRelationshipHyperLink)))
|
||||||
pics, err = f.GetPictures("Sheet1", "A1")
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, pics)
|
assert.Empty(t, pics)
|
||||||
// Test get the Microsoft 365 cell images with unsupported charset rich data rich value relationships
|
// Test get the cell images with unsupported charset rich data rich value relationships
|
||||||
f.Relationships.Delete(defaultXMLRichDataRichValueRelRels)
|
f.Relationships.Delete(defaultXMLRichDataRichValueRelRels)
|
||||||
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, MacintoshCyrillicCharset)
|
f.Pkg.Store(defaultXMLRichDataRichValueRelRels, MacintoshCyrillicCharset)
|
||||||
pics, err = f.GetPictures("Sheet1", "A1")
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, pics)
|
assert.Empty(t, pics)
|
||||||
// Test get the Microsoft 365 cell images with unsupported charset rich data rich value
|
// Test get the cell images with unsupported charset rich data rich value
|
||||||
f.Pkg.Store(defaultXMLRichDataRichValueRel, MacintoshCyrillicCharset)
|
f.Pkg.Store(defaultXMLRichDataRichValueRel, MacintoshCyrillicCharset)
|
||||||
_, err = f.GetPictures("Sheet1", "A1")
|
_, err = f.GetPictures("Sheet1", "A1")
|
||||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
// Test get the Microsoft 365 image cells without block of metadata records
|
// Test get the image cells without block of metadata records
|
||||||
cells, err = f.GetPictureCells("Sheet1")
|
cells, err = f.GetPictureCells("Sheet1")
|
||||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
assert.Empty(t, cells)
|
assert.Empty(t, cells)
|
||||||
// Test get the Microsoft 365 cell images with rich data rich value relationships
|
// Test get the cell images with rich data rich value relationships
|
||||||
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata count="1"><bk><rc t="1" v="0"/></bk></valueMetadata></metadata>`))
|
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata count="1"><bk><rc t="1" v="0"/></bk></valueMetadata></metadata>`))
|
||||||
f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(`<richValueRels/>`))
|
f.Pkg.Store(defaultXMLRichDataRichValueRel, []byte(`<richValueRels/>`))
|
||||||
pics, err = f.GetPictures("Sheet1", "A1")
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, pics)
|
assert.Empty(t, pics)
|
||||||
// Test get the Microsoft 365 cell images with unsupported charset meta data
|
// Test get the cell images with unsupported charset meta data
|
||||||
f.Pkg.Store(defaultXMLMetadata, MacintoshCyrillicCharset)
|
f.Pkg.Store(defaultXMLMetadata, MacintoshCyrillicCharset)
|
||||||
_, err = f.GetPictures("Sheet1", "A1")
|
_, err = f.GetPictures("Sheet1", "A1")
|
||||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
// Test get the Microsoft 365 cell images without block of metadata records
|
// Test get the cell images without block of metadata records
|
||||||
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata/></metadata>`))
|
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata/></metadata>`))
|
||||||
pics, err = f.GetPictures("Sheet1", "A1")
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, pics)
|
assert.Empty(t, pics)
|
||||||
|
|
||||||
|
f = prepareWorkbook()
|
||||||
|
// Test get the cell images with empty image cell rich value
|
||||||
|
f.Pkg.Store(defaultXMLRichDataRichValue, []byte(`<rvData count="1"><rv s="0"><v></v><v>5</v></rv></rvData>`))
|
||||||
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
|
assert.EqualError(t, err, "strconv.Atoi: parsing \"\": invalid syntax")
|
||||||
|
assert.Empty(t, pics)
|
||||||
|
// Test get the cell images without image cell rich value
|
||||||
|
f.Pkg.Store(defaultXMLRichDataRichValue, []byte(`<rvData count="1"><rv s="0"><v>0</v><v>1</v></rv></rvData>`))
|
||||||
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, pics)
|
||||||
|
// Test get the cell images with unsupported charset rich value
|
||||||
|
f.Pkg.Store(defaultXMLRichDataRichValue, MacintoshCyrillicCharset)
|
||||||
|
_, err = f.GetPictures("Sheet1", "A1")
|
||||||
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
|
|
||||||
|
f = prepareWorkbook()
|
||||||
|
// Test get the cell images with invalid rich value index
|
||||||
|
f.Pkg.Store(defaultXMLMetadata, []byte(`<metadata><valueMetadata count="1"><bk><rc t="1" v="1"/></bk></valueMetadata></metadata>`))
|
||||||
|
pics, err = f.GetPictures("Sheet1", "A1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, pics)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetImageCells(t *testing.T) {
|
func TestGetImageCells(t *testing.T) {
|
||||||
|
|
|
@ -280,6 +280,7 @@ const (
|
||||||
defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml"
|
defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml"
|
||||||
defaultXMLPathWorkbook = "xl/workbook.xml"
|
defaultXMLPathWorkbook = "xl/workbook.xml"
|
||||||
defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels"
|
defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels"
|
||||||
|
defaultXMLRichDataRichValue = "xl/richData/rdrichvalue.xml"
|
||||||
defaultXMLRichDataRichValueRel = "xl/richData/richValueRel.xml"
|
defaultXMLRichDataRichValueRel = "xl/richData/richValueRel.xml"
|
||||||
defaultXMLRichDataRichValueRelRels = "xl/richData/_rels/richValueRel.xml.rels"
|
defaultXMLRichDataRichValueRelRels = "xl/richData/_rels/richValueRel.xml.rels"
|
||||||
)
|
)
|
||||||
|
|
|
@ -68,6 +68,23 @@ type xlsxMetadataRecord struct {
|
||||||
V int `xml:"v,attr"`
|
V int `xml:"v,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xlsxRichValueData directly maps the rvData element that specifies rich value
|
||||||
|
// data.
|
||||||
|
type xlsxRichValueData struct {
|
||||||
|
XMLName xml.Name `xml:"rvData"`
|
||||||
|
Count int `xml:"count,attr,omitempty"`
|
||||||
|
Rv []xlsxRichValue `xml:"rv"`
|
||||||
|
ExtLst *xlsxInnerXML `xml:"extLst"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// xlsxRichValue directly maps the rv element that specifies rich value data
|
||||||
|
// information for a single rich value
|
||||||
|
type xlsxRichValue struct {
|
||||||
|
S int `xml:"s,attr"`
|
||||||
|
V []string `xml:"v"`
|
||||||
|
Fb *xlsxInnerXML `xml:"fb"`
|
||||||
|
}
|
||||||
|
|
||||||
// xlsxRichValueRels directly maps the richValueRels element. This element that
|
// xlsxRichValueRels directly maps the richValueRels element. This element that
|
||||||
// specifies a list of rich value relationships.
|
// specifies a list of rich value relationships.
|
||||||
type xlsxRichValueRels struct {
|
type xlsxRichValueRels struct {
|
||||||
|
|
Loading…
Reference in New Issue