From b2f3556e8d5a88f07d51e45c164bcc4d3322b4f4 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 08:53:48 +0500 Subject: [PATCH 01/28] feat: added array data values structs --- xmlMetaData.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/xmlMetaData.go b/xmlMetaData.go index 016e348674..18c27ad8aa 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -68,6 +68,30 @@ type xlsxMetadataRecord struct { V int `xml:"v,attr"` } +// xlsxRichValueArrayData directly maps the arrayData element that specifies rich value +// arrays. +type XlsxRichValueArrayData struct { + XMLName xml.Name `xml:"arrayData"` + Xmlns string `xml:"xmlns,attr"` + Count string `xml:"count,attr"` + A XlsxRichValuesArray `xml:"a"` +} + +// xlsxRichValuesArray directly maps the a element that specifies rich values Array +// information for an array data +type XlsxRichValuesArray struct { + R string `xml:"r,attr"` + C string `xml:"c,attr"` + V []XlsxRichArrayValue `xml:"v"` +} + +// XlsxRichArrayValue directly maps the v element that specifies rich array value +// information for a values array +type XlsxRichArrayValue struct { + Text string `xml:",chardata"` + T string `xml:"t,attr"` +} + // xlsxRichValueData directly maps the rvData element that specifies rich value // data. type xlsxRichValueData struct { From 4cfd8802111b0a2f586f72421207d52505a1f346 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 08:54:41 +0500 Subject: [PATCH 02/28] feat: add rich data value default xmls --- templates.go | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/templates.go b/templates.go index 3bf4c5fe69..3534d945a0 100644 --- a/templates.go +++ b/templates.go @@ -266,25 +266,31 @@ var supportedChartDataLabelsPosition = map[ChartType][]ChartDataLabelPositionTyp } const ( - defaultTempFileSST = "sharedStrings" - defaultXMLMetadata = "xl/metadata.xml" - defaultXMLPathCalcChain = "xl/calcChain.xml" - defaultXMLPathCellImages = "xl/cellimages.xml" - defaultXMLPathCellImagesRels = "xl/_rels/cellimages.xml.rels" - defaultXMLPathContentTypes = "[Content_Types].xml" - defaultXMLPathDocPropsApp = "docProps/app.xml" - defaultXMLPathDocPropsCore = "docProps/core.xml" - defaultXMLPathSharedStrings = "xl/sharedStrings.xml" - defaultXMLPathStyles = "xl/styles.xml" - defaultXMLPathTheme = "xl/theme/theme1.xml" - defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml" - defaultXMLPathWorkbook = "xl/workbook.xml" - defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels" - defaultXMLRdRichValuePart = "xl/richData/rdrichvalue.xml" - defaultXMLRdRichValueRel = "xl/richData/richValueRel.xml" - defaultXMLRdRichValueRelRels = "xl/richData/_rels/richValueRel.xml.rels" - defaultXMLRdRichValueWebImagePart = "xl/richData/rdRichValueWebImage.xml" - defaultXMLRdRichValueWebImagePartRels = "xl/richData/_rels/rdRichValueWebImage.xml.rels" + defaultTempFileSST = "sharedStrings" + defaultXMLMetadata = "xl/metadata.xml" + defaultXMLPathCalcChain = "xl/calcChain.xml" + defaultXMLPathCellImages = "xl/cellimages.xml" + defaultXMLPathCellImagesRels = "xl/_rels/cellimages.xml.rels" + defaultXMLPathContentTypes = "[Content_Types].xml" + defaultXMLPathDocPropsApp = "docProps/app.xml" + defaultXMLPathDocPropsCore = "docProps/core.xml" + defaultXMLPathSharedStrings = "xl/sharedStrings.xml" + defaultXMLPathStyles = "xl/styles.xml" + defaultXMLPathTheme = "xl/theme/theme1.xml" + defaultXMLPathVolatileDeps = "xl/volatileDependencies.xml" + defaultXMLPathWorkbook = "xl/workbook.xml" + defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels" + defaultXMLRdRichValuePart = "xl/richData/rdrichvalue.xml" + defaultXMLRdRichValueRel = "xl/richData/richValueRel.xml" + defaultXMLRdRichValueRelRels = "xl/richData/_rels/richValueRel.xml.rels" + defaultXMLRdRichValueWebImagePart = "xl/richData/rdRichValueWebImage.xml" + defaultXMLRdRichValueWebImagePartRels = "xl/richData/_rels/rdRichValueWebImage.xml.rels" + defaultXMLRichDataArray = "xl/richData/rdarray.xml" + defaultXMLRichDataRichValueStructure = "xl/richData/rdrichvaluestructure.xml" + defaultXMLRichDataRichValueTypes = "xl/richData/rdRichValueTypes.xml" + defaultXMLRichDataSupportingPropertyBag = "xl/richData/rdsupportingpropertybag.xml" + defaultXMLRichDataSupportingPropertyBagStructure = "xl/richData/rdsupportingpropertybagstructure.xml" + defaultXMLRichDataRichStyles = "xl/richData/richStyles.xml" ) // IndexedColorMapping is the table of default mappings from indexed color value From 1acc467c9513fe138230716e8fc68b48691043c4 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 11:51:03 +0500 Subject: [PATCH 03/28] feat: add rich value structure and spb --- xmlMetaData.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/xmlMetaData.go b/xmlMetaData.go index 18c27ad8aa..adf66c0181 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -123,6 +123,51 @@ type xlsxRichValueRelRelationship struct { ID string `xml:"id,attr"` } +// XlsxRichValueStructures directly maps the rvStructures element that specifies rich value structure +// data. +type XlsxRichValueStructures struct { + XMLName xml.Name `xml:"rvStructures"` + Text string `xml:",chardata"` + Xmlns string `xml:"xmlns,attr"` + Count string `xml:"count,attr"` + S []XlsxRichValueStructure `xml:"s"` +} + +// XlsxRichValueStructure directly maps the s element that specifies rich value structure data +// information for a single rich value structure +type XlsxRichValueStructure struct { + Text string `xml:",chardata"` + T string `xml:"t,attr"` + K []XlsxRichValueStructureKey `xml:"k"` +} + +// XlsxRichValueStructureKey directly maps the k element that specifies rich value structure key data +// information for a structure +type XlsxRichValueStructureKey struct { + Text string `xml:",chardata"` + N string `xml:"n,attr"` + T string `xml:"t,attr"` +} + +type XlsxRichDataSupportingPropertyBags struct { + XMLName xml.Name `xml:"supportingPropertyBags"` + Text string `xml:",chardata"` + Xmlns string `xml:"xmlns,attr"` + SpbData XlsxRichDataSpbData `xml:"spbData"` +} + +type XlsxRichDataSpbData struct { + Text string `xml:",chardata"` + Count string `xml:"count,attr"` + Spb []XlsxRichDataSpb `xml:"spb"` +} + +type XlsxRichDataSpb struct { + Text string `xml:",chardata"` + S string `xml:"s,attr"` + V []string `xml:"v"` +} + // xlsxWebImagesSupportingRichData directly maps the webImagesSrd element. This // element specifies a list of sets of properties associated with web image rich // values. From 64ea19dbce08f331c273261371a12ab1d705f76a Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 12:30:17 +0500 Subject: [PATCH 04/28] comment: added for spbdata structs --- xmlMetaData.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xmlMetaData.go b/xmlMetaData.go index adf66c0181..e4996edb5d 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -149,6 +149,7 @@ type XlsxRichValueStructureKey struct { T string `xml:"t,attr"` } +// XlsxRichDataSupportingPropertyBags directly maps the supportingPropertyBags element that specifies supporting property bag data. type XlsxRichDataSupportingPropertyBags struct { XMLName xml.Name `xml:"supportingPropertyBags"` Text string `xml:",chardata"` @@ -156,12 +157,14 @@ type XlsxRichDataSupportingPropertyBags struct { SpbData XlsxRichDataSpbData `xml:"spbData"` } +// XlsxRichDataSpbData directly maps the spbData element that specifies supporting property bag data. type XlsxRichDataSpbData struct { Text string `xml:",chardata"` Count string `xml:"count,attr"` Spb []XlsxRichDataSpb `xml:"spb"` } +// XlsxRichDataSpb directly maps the spb element that specifies data for a single supporting property bag. type XlsxRichDataSpb struct { Text string `xml:",chardata"` S string `xml:"s,attr"` From c3741bbc0f41b20218004dc18ad7672f30c57709 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 14:15:04 +0500 Subject: [PATCH 05/28] feat: added richDataSpbStructure structs --- xmlMetaData.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/xmlMetaData.go b/xmlMetaData.go index e4996edb5d..5304565524 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -171,6 +171,28 @@ type XlsxRichDataSpb struct { V []string `xml:"v"` } +// XlsxRichDataSpbStructures directly maps the spbStructures element that specifies supporting property bag structure. +type XlsxRichDataSpbStructures struct { + XMLName xml.Name `xml:"spbStructures"` + Text string `xml:",chardata"` + Xmlns string `xml:"xmlns,attr"` + Count string `xml:"count,attr"` + S []XlsxRichDataSpbStructure `xml:"s"` +} + +// XlsxRichDataSpbStructure directly maps the s element that specifies spb structure information for a single spb structure +type XlsxRichDataSpbStructure struct { + Text string `xml:",chardata"` + K []XlsxRichDataSpbStructureKey `xml:"k"` +} + +// XlsxRichDataSpbStructureKey directly maps the k element that specifies spb structure key data and attributes information for a single spb structure +type XlsxRichDataSpbStructureKey struct { + Text string `xml:",chardata"` + N string `xml:"n,attr"` + T string `xml:"t,attr"` +} + // xlsxWebImagesSupportingRichData directly maps the webImagesSrd element. This // element specifies a list of sets of properties associated with web image rich // values. From ea250fad0eff56081c9f7236bfeab5f0b647748d Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 14:54:59 +0500 Subject: [PATCH 06/28] fix: change private structs --- xmlMetaData.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/xmlMetaData.go b/xmlMetaData.go index 5304565524..f551f51463 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -74,20 +74,20 @@ type XlsxRichValueArrayData struct { XMLName xml.Name `xml:"arrayData"` Xmlns string `xml:"xmlns,attr"` Count string `xml:"count,attr"` - A XlsxRichValuesArray `xml:"a"` + A xlsxRichValuesArray `xml:"a"` } // xlsxRichValuesArray directly maps the a element that specifies rich values Array // information for an array data -type XlsxRichValuesArray struct { +type xlsxRichValuesArray struct { R string `xml:"r,attr"` C string `xml:"c,attr"` - V []XlsxRichArrayValue `xml:"v"` + V []xlsxRichArrayValue `xml:"v"` } // XlsxRichArrayValue directly maps the v element that specifies rich array value // information for a values array -type XlsxRichArrayValue struct { +type xlsxRichArrayValue struct { Text string `xml:",chardata"` T string `xml:"t,attr"` } @@ -130,20 +130,20 @@ type XlsxRichValueStructures struct { Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` Count string `xml:"count,attr"` - S []XlsxRichValueStructure `xml:"s"` + S []xlsxRichValueStructure `xml:"s"` } // XlsxRichValueStructure directly maps the s element that specifies rich value structure data // information for a single rich value structure -type XlsxRichValueStructure struct { +type xlsxRichValueStructure struct { Text string `xml:",chardata"` T string `xml:"t,attr"` - K []XlsxRichValueStructureKey `xml:"k"` + K []xlsxRichValueStructureKey `xml:"k"` } // XlsxRichValueStructureKey directly maps the k element that specifies rich value structure key data // information for a structure -type XlsxRichValueStructureKey struct { +type xlsxRichValueStructureKey struct { Text string `xml:",chardata"` N string `xml:"n,attr"` T string `xml:"t,attr"` @@ -154,18 +154,18 @@ type XlsxRichDataSupportingPropertyBags struct { XMLName xml.Name `xml:"supportingPropertyBags"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` - SpbData XlsxRichDataSpbData `xml:"spbData"` + SpbData xlsxRichDataSpbData `xml:"spbData"` } // XlsxRichDataSpbData directly maps the spbData element that specifies supporting property bag data. -type XlsxRichDataSpbData struct { +type xlsxRichDataSpbData struct { Text string `xml:",chardata"` Count string `xml:"count,attr"` - Spb []XlsxRichDataSpb `xml:"spb"` + Spb []xlsxRichDataSpb `xml:"spb"` } // XlsxRichDataSpb directly maps the spb element that specifies data for a single supporting property bag. -type XlsxRichDataSpb struct { +type xlsxRichDataSpb struct { Text string `xml:",chardata"` S string `xml:"s,attr"` V []string `xml:"v"` @@ -177,17 +177,17 @@ type XlsxRichDataSpbStructures struct { Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` Count string `xml:"count,attr"` - S []XlsxRichDataSpbStructure `xml:"s"` + S []xlsxRichDataSpbStructure `xml:"s"` } // XlsxRichDataSpbStructure directly maps the s element that specifies spb structure information for a single spb structure -type XlsxRichDataSpbStructure struct { +type xlsxRichDataSpbStructure struct { Text string `xml:",chardata"` - K []XlsxRichDataSpbStructureKey `xml:"k"` + K []xlsxRichDataSpbStructureKey `xml:"k"` } // XlsxRichDataSpbStructureKey directly maps the k element that specifies spb structure key data and attributes information for a single spb structure -type XlsxRichDataSpbStructureKey struct { +type xlsxRichDataSpbStructureKey struct { Text string `xml:",chardata"` N string `xml:"n,attr"` T string `xml:"t,attr"` From 06e55163f7d09844d2bbfd037565b3e8f511d09c Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 5 Apr 2024 15:57:16 +0500 Subject: [PATCH 07/28] fix: make all richData structs private with public access methods --- xmlMetaData.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xmlMetaData.go b/xmlMetaData.go index f551f51463..d5b3624184 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -70,7 +70,7 @@ type xlsxMetadataRecord struct { // xlsxRichValueArrayData directly maps the arrayData element that specifies rich value // arrays. -type XlsxRichValueArrayData struct { +type xlsxRichValueArrayData struct { XMLName xml.Name `xml:"arrayData"` Xmlns string `xml:"xmlns,attr"` Count string `xml:"count,attr"` @@ -125,7 +125,7 @@ type xlsxRichValueRelRelationship struct { // XlsxRichValueStructures directly maps the rvStructures element that specifies rich value structure // data. -type XlsxRichValueStructures struct { +type xlsxRichValueStructures struct { XMLName xml.Name `xml:"rvStructures"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` @@ -172,7 +172,7 @@ type xlsxRichDataSpb struct { } // XlsxRichDataSpbStructures directly maps the spbStructures element that specifies supporting property bag structure. -type XlsxRichDataSpbStructures struct { +type xlsxRichDataSpbStructures struct { XMLName xml.Name `xml:"spbStructures"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` From b7bcf4b1f8eb13f76fcc2a2501d238a2c501b7f8 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Tue, 9 Apr 2024 08:29:30 +0500 Subject: [PATCH 08/28] added types and styles structs richdata --- xmlMetaData.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/xmlMetaData.go b/xmlMetaData.go index d5b3624184..80c42e2dfb 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -104,9 +104,9 @@ type xlsxRichValueData struct { // 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"` + S int `xml:"s,attr"` + V []string `xml:"v"` + Fb string `xml:"fb"` } // xlsxRichValueRels directly maps the richValueRels element. This element that @@ -193,6 +193,100 @@ type xlsxRichDataSpbStructureKey struct { T string `xml:"t,attr"` } +type RvTypesInfo struct { + XMLName xml.Name `xml:"rvTypesInfo"` + Text string `xml:",chardata"` + Xmlns string `xml:"xmlns,attr"` + Mc string `xml:"mc,attr"` + Ignorable string `xml:"Ignorable,attr"` + X string `xml:"x,attr"` + Global Global `xml:"global"` +} + +type Global struct { + Text string `xml:",chardata"` + KeyFlags KeyFlags `xml:"keyFlags"` +} +type KeyFlags struct { + Text string `xml:",chardata"` + Key []Key `xml:"key"` +} +type Key struct { + Text string `xml:",chardata"` + Name string `xml:"name,attr"` + Flag []Flag `xml:"flag"` +} +type Flag struct { + Text string `xml:",chardata"` + Name string `xml:"name,attr"` + Value string `xml:"value,attr"` +} + +// this is where the richdatatyle file starts +type RichStyleSheet struct { + XMLName xml.Name `xml:"richStyleSheet"` + Text string `xml:",chardata"` + Xmlns string `xml:"xmlns,attr"` + Mc string `xml:"mc,attr"` + Ignorable string `xml:"Ignorable,attr"` + X string `xml:"x,attr"` + Dxfs Dxfs `xml:"dxfs"` + RichProperties RichProperties `xml:"richProperties"` + RichStyles RichStyles `xml:"richStyles"` +} + +// Dxfs struct is for the element. +type Dxfs struct { + Text string `xml:",chardata"` + Count string `xml:"count,attr"` + Dxf []Dxf `xml:"dxf"` +} + +// Dxf struct is for the elements within . +type Dxf struct { + Text string `xml:",chardata"` + NumFmt NumFmt `xml:"numFmt"` +} + +// NumFmt struct is for the element within . +type NumFmt struct { + Text string `xml:",chardata"` + NumFmtId string `xml:"numFmtId,attr"` + FormatCode string `xml:"formatCode,attr"` +} + +// RichProperties struct is for the element. +type RichProperties struct { + Text string `xml:",chardata"` + RPr RPr `xml:"rPr"` +} + +// RPr struct is for the element within . +type RPr struct { + Text string `xml:",chardata"` + N string `xml:"n,attr"` + T string `xml:"t,attr"` +} + +// RichStyles struct is for the element. +type RichStyles struct { + Text string `xml:",chardata"` + RSty []RSty `xml:"rSty"` +} + +// RSty struct is for the elements within . +type RSty struct { + Text string `xml:",chardata"` + Dxfid string `xml:"dxfid,attr"` + Rpv Rpv `xml:"rpv"` +} + +// Rpv struct is for the element within . +type Rpv struct { + Text string `xml:",chardata"` + I string `xml:"i,attr"` +} + // xlsxWebImagesSupportingRichData directly maps the webImagesSrd element. This // element specifies a list of sets of properties associated with web image rich // values. From c12aa355c4a37cd2bfdb64c9e1a9ab76c57e5387 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Tue, 9 Apr 2024 08:29:54 +0500 Subject: [PATCH 09/28] add richdata sample tests --- rich_data_test.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 rich_data_test.go diff --git a/rich_data_test.go b/rich_data_test.go new file mode 100644 index 0000000000..c8f71f4fc3 --- /dev/null +++ b/rich_data_test.go @@ -0,0 +1,84 @@ +package excelize + +import ( + "bytes" + "fmt" + "io" + "testing" +) + +func TestRichDataInsert(t *testing.T) { + f := NewFile() + f.Pkg.Store(defaultXMLMetadata, []byte(``)) + f.Pkg.Store(defaultXMLRdRichValuePart, []byte(`05`)) + f.Pkg.Store(defaultXMLRdRichValueRel, []byte(``)) + f.Pkg.Store(defaultXMLRdRichValueRelRels, []byte(fmt.Sprintf(``, SourceRelationshipImage))) + 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)}}}, + }}, + }) +} + +func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { + var richValue xlsxRichValueData + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). + Decode(&richValue); err != nil && err != io.EOF { + return &richValue, err + } + return &richValue, nil +} + +func (f *File) TestRichValueArrayDataReader() (*xlsxRichValueArrayData, error) { + var richValueArray xlsxRichValueArrayData + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataArray)))). + Decode(&richValueArray); err != nil && err != io.EOF { + return &richValueArray, err + } + return &richValueArray, nil +} + +func (f *File) TestRichValueStructureReader() (*xlsxRichValueStructures, error) { + var richValueStructures xlsxRichValueStructures + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueStructure)))). + Decode(&richValueStructures); err != nil && err != io.EOF { + return &richValueStructures, err + } + return &richValueStructures, nil +} + +func (f *File) TestRichDataSpb() (*XlsxRichDataSupportingPropertyBags, error) { + var richDataSpb XlsxRichDataSupportingPropertyBags + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBag)))). + Decode(&richDataSpb); err != nil && err != io.EOF { + return &richDataSpb, err + } + return &richDataSpb, nil +} + +func (f *File) TestRichDataSpbStructure() (*xlsxRichDataSpbStructures, error) { + var richDataSpbStructure xlsxRichDataSpbStructures + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBagStructure)))). + Decode(&richDataSpbStructure); err != nil && err != io.EOF { + return &richDataSpbStructure, err + } + return &richDataSpbStructure, nil +} + +func (f *File) TestRichDataStyles() (*RichStyleSheet, error) { + var richDataStyle RichStyleSheet + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichStyles)))). + Decode(&richDataStyle); err != nil && err != io.EOF { + return &richDataStyle, err + } + return &richDataStyle, nil +} + +func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { + var richDataTypes RvTypesInfo + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueTypes)))). + Decode(&richDataTypes); err != nil && err != io.EOF { + return &richDataTypes, err + } + return &richDataTypes, nil +} From b899a39c8da6a40f290a4d2e815adf894ec30a6a Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Tue, 9 Apr 2024 08:38:10 +0500 Subject: [PATCH 10/28] move tests file --- excelize.go | 63 +++++++++++++++++++++++++++++++++++++++++++++ rich_data_test.go | 65 ----------------------------------------------- 2 files changed, 63 insertions(+), 65 deletions(-) diff --git a/excelize.go b/excelize.go index e0959aa646..8d0e651654 100644 --- a/excelize.go +++ b/excelize.go @@ -612,6 +612,69 @@ func (f *File) richValueReader() (*xlsxRichValueData, error) { return &richValue, nil } +func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { + var richValue xlsxRichValueData + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). + Decode(&richValue); err != nil && err != io.EOF { + return &richValue, err + } + return &richValue, nil +} + +func (f *File) TestRichValueArrayDataReader() (*xlsxRichValueArrayData, error) { + var richValueArray xlsxRichValueArrayData + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataArray)))). + Decode(&richValueArray); err != nil && err != io.EOF { + return &richValueArray, err + } + return &richValueArray, nil +} + +func (f *File) TestRichValueStructureReader() (*xlsxRichValueStructures, error) { + var richValueStructures xlsxRichValueStructures + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueStructure)))). + Decode(&richValueStructures); err != nil && err != io.EOF { + return &richValueStructures, err + } + return &richValueStructures, nil +} + +func (f *File) TestRichDataSpb() (*XlsxRichDataSupportingPropertyBags, error) { + var richDataSpb XlsxRichDataSupportingPropertyBags + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBag)))). + Decode(&richDataSpb); err != nil && err != io.EOF { + return &richDataSpb, err + } + return &richDataSpb, nil +} + +func (f *File) TestRichDataSpbStructure() (*xlsxRichDataSpbStructures, error) { + var richDataSpbStructure xlsxRichDataSpbStructures + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBagStructure)))). + Decode(&richDataSpbStructure); err != nil && err != io.EOF { + return &richDataSpbStructure, err + } + return &richDataSpbStructure, nil +} + +func (f *File) TestRichDataStyles() (*RichStyleSheet, error) { + var richDataStyle RichStyleSheet + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichStyles)))). + Decode(&richDataStyle); err != nil && err != io.EOF { + return &richDataStyle, err + } + return &richDataStyle, nil +} + +func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { + var richDataTypes RvTypesInfo + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueTypes)))). + Decode(&richDataTypes); err != nil && err != io.EOF { + return &richDataTypes, err + } + return &richDataTypes, nil +} + // richValueRelReader provides a function to get the pointer to the structure // after deserialization of xl/richData/richValueRel.xml. func (f *File) richValueRelReader() (*xlsxRichValueRels, error) { diff --git a/rich_data_test.go b/rich_data_test.go index c8f71f4fc3..0f14bcb6bb 100644 --- a/rich_data_test.go +++ b/rich_data_test.go @@ -1,9 +1,7 @@ package excelize import ( - "bytes" "fmt" - "io" "testing" ) @@ -19,66 +17,3 @@ func TestRichDataInsert(t *testing.T) { }}, }) } - -func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { - var richValue xlsxRichValueData - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). - Decode(&richValue); err != nil && err != io.EOF { - return &richValue, err - } - return &richValue, nil -} - -func (f *File) TestRichValueArrayDataReader() (*xlsxRichValueArrayData, error) { - var richValueArray xlsxRichValueArrayData - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataArray)))). - Decode(&richValueArray); err != nil && err != io.EOF { - return &richValueArray, err - } - return &richValueArray, nil -} - -func (f *File) TestRichValueStructureReader() (*xlsxRichValueStructures, error) { - var richValueStructures xlsxRichValueStructures - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueStructure)))). - Decode(&richValueStructures); err != nil && err != io.EOF { - return &richValueStructures, err - } - return &richValueStructures, nil -} - -func (f *File) TestRichDataSpb() (*XlsxRichDataSupportingPropertyBags, error) { - var richDataSpb XlsxRichDataSupportingPropertyBags - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBag)))). - Decode(&richDataSpb); err != nil && err != io.EOF { - return &richDataSpb, err - } - return &richDataSpb, nil -} - -func (f *File) TestRichDataSpbStructure() (*xlsxRichDataSpbStructures, error) { - var richDataSpbStructure xlsxRichDataSpbStructures - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBagStructure)))). - Decode(&richDataSpbStructure); err != nil && err != io.EOF { - return &richDataSpbStructure, err - } - return &richDataSpbStructure, nil -} - -func (f *File) TestRichDataStyles() (*RichStyleSheet, error) { - var richDataStyle RichStyleSheet - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichStyles)))). - Decode(&richDataStyle); err != nil && err != io.EOF { - return &richDataStyle, err - } - return &richDataStyle, nil -} - -func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { - var richDataTypes RvTypesInfo - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueTypes)))). - Decode(&richDataTypes); err != nil && err != io.EOF { - return &richDataTypes, err - } - return &richDataTypes, nil -} From c8bbea4f818ea75c8bbe264c717705f741f3bd4a Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Tue, 23 Apr 2024 16:19:22 +0500 Subject: [PATCH 11/28] feat: integrate spb read with excelize --- excelize.go | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ templates.go | 6 ++ xmlMetaData.go | 9 ++- 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/excelize.go b/excelize.go index 8d0e651654..945b0d4c9d 100644 --- a/excelize.go +++ b/excelize.go @@ -16,7 +16,10 @@ import ( "archive/zip" "bytes" "encoding/xml" + "errors" + "fmt" "io" + "log" "os" "path/filepath" "strconv" @@ -612,6 +615,24 @@ func (f *File) richValueReader() (*xlsxRichValueData, error) { return &richValue, nil } +func (f *File) richStructureReader() (*xlsxRichValueStructures, error) { + var richValueStructures xlsxRichValueStructures + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueStructure)))). + Decode(&richValueStructures); err != nil && err != io.EOF { + return &richValueStructures, err + } + return &richValueStructures, nil +} + +func (f *File) richDataSpbReader() (*XlsxRichDataSupportingPropertyBags, error) { + var richDataspbs XlsxRichDataSupportingPropertyBags + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBag)))). + Decode(&richDataspbs); err != nil && err != io.EOF { + return &richDataspbs, err + } + return &richDataspbs, nil +} + func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { var richValue xlsxRichValueData if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). @@ -675,6 +696,141 @@ func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { return &richDataTypes, nil } +// func (f *File) TestArrayData(sheet string) error { +// if err := checkSheetName(sheet); err != nil { +// return err +// } +// name := defaultXMLRichDataArray +// if xmlFile, ok := f.Sheet.Load(name); ok && xmlFile != nil { +// var arrayData xlsxRichValueArrayData +// output, _ := xml.Marshal(arrayData) +// f.saveFileList(name, f.replaceNameSpaceBytes(name, output)) +// } +// return nil +// } + +func (f *File) CheckOrCreateRichData() { + f.CheckOrCreateXML(defaultXMLRdRichValuePart, []byte(xml.Header+templateRichValue)) + f.CheckOrCreateXML(defaultXMLRichDataRichValueStructure, []byte(xml.Header+templateRichStructure)) + f.CheckOrCreateXML(defaultXMLRichDataRichValueTypes, []byte(xml.Header+templateRichValuetypes)) +} + +func (f *File) CheckOrCreateXML(name string, defaultContent []byte) { + // Check if the XML file exists + if _, ok := f.Pkg.Load(name); !ok { + // The XML file does not exist, so create it with the default content + f.Pkg.Store(name, defaultContent) + } +} + +func (f *File) AddEntity(sheet, cell, entityData string) { + f.CheckOrCreateRichData() + // marshal the entity data and store inside files accordingly +} + +func (f *File) ReadEntity(sheet, cell string) (string, error) { + + cellType, err := f.GetCellType(sheet, cell) + if err != nil { + return "", err + } + if cellType != 3 { + return "", errors.New("Cell is not of type entity") + } + + metadata, err := f.metadataReader() + if err != nil { + return "", err + } + + ws, _ := f.workSheetReader(sheet) + ws.mu.Lock() + defer ws.mu.Unlock() + + for _, row := range ws.SheetData.Row { + for _, c := range row.C { + if c.R == cell { + + cellMetadataIdx := *c.Vm - 1 + richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I + richValue, err := f.richValueReader() + if err != nil { + return "", err + } + if richValueIdx >= len(richValue.Rv) { + return "", err + } + + cellRichData := richValue.Rv[richValueIdx] + + richValueStructure, err := f.richStructureReader() + if err != nil { + return "", err + } + + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return "", err + } + + for cellRichDataIdx, cellRichDataValue := range cellRichData.V { + cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] + + print("\n\n") + fmt.Println(cellRichStructure) + fmt.Println(cellRichDataValue) + + if cellRichStructure.T == "" { + fmt.Println("Key is:") + fmt.Println(cellRichStructure.N) + fmt.Println("Value is:") + fmt.Println(cellRichDataValue) + } else if cellRichStructure.T == "s" { + if cellRichStructure.N[0] == '_' { + fmt.Println("Value is richdata special formatted") + // more if else here + if cellRichStructure.N == "_DisplayString" { + fmt.Println("Outermost value which will be shown inside the cell") + } else if cellRichStructure.N == "_Icon" { + fmt.Println("Outermost icon which will be shown inside the cell") + } + } + } else if cellRichStructure.T == "b" { + fmt.Println("Value is boolean") // 1=true, 0=false + fmt.Println("Key is:") + fmt.Println(cellRichStructure.N) + fmt.Println("Value is:") + boolValue := cellRichDataValue == "1" + fmt.Println(boolValue) + } else if cellRichStructure.T == "r" { + fmt.Println("Value is of type formatted string or entity or image") + } else if cellRichStructure.T == "spb" { + fmt.Println("Value is of type spb") + // lots of work needed here + fmt.Println("SPB index is:") + spbIndex, err := strconv.Atoi(cellRichDataValue) + if err != nil { + log.Fatal(err) + } + fmt.Println(spbIndex) + fmt.Println("SPB value is:") + fmt.Println(richDataSpbs.SpbData.Spb[spbIndex]) + if cellRichStructure.N == "_Provider" { + fmt.Println("Footer data with text and logo:") + fmt.Println(richDataSpbs.SpbData.Spb[spbIndex].V) + // can there be multiple providers for one card? What about provider logo + } + } else if cellRichStructure.T == "a" { + fmt.Println("Value is of type array") + // array data was mapped. Can reuse code + } + } + } + } + } + return "", err +} + // richValueRelReader provides a function to get the pointer to the structure // after deserialization of xl/richData/richValueRel.xml. func (f *File) richValueRelReader() (*xlsxRichValueRels, error) { diff --git a/templates.go b/templates.go index 3534d945a0..37310d9f84 100644 --- a/templates.go +++ b/templates.go @@ -522,3 +522,9 @@ const templateRels = `` const templateNamespaceIDMap = ` xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:ap="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:op="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:cdr="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" xmlns:comp="http://schemas.openxmlformats.org/drawingml/2006/compatibility" xmlns:dgm="http://schemas.openxmlformats.org/drawingml/2006/diagram" xmlns:lc="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:xne="http://schemas.microsoft.com/office/excel/2006/main" xmlns:mso="http://schemas.microsoft.com/office/2006/01/customui" xmlns:ax="http://schemas.microsoft.com/office/2006/activeX" xmlns:cppr="http://schemas.microsoft.com/office/2006/coverPageProps" xmlns:cdip="http://schemas.microsoft.com/office/2006/customDocumentInformationPanel" xmlns:ct="http://schemas.microsoft.com/office/2006/metadata/contentType" xmlns:ntns="http://schemas.microsoft.com/office/2006/metadata/customXsn" xmlns:lp="http://schemas.microsoft.com/office/2006/metadata/longProperties" xmlns:ma="http://schemas.microsoft.com/office/2006/metadata/properties/metaAttributes" xmlns:msink="http://schemas.microsoft.com/ink/2010/main" xmlns:c14="http://schemas.microsoft.com/office/drawing/2007/8/2/chart" xmlns:cdr14="http://schemas.microsoft.com/office/drawing/2010/chartDrawing" xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" xmlns:pic14="http://schemas.microsoft.com/office/drawing/2010/picture" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:xdr14="http://schemas.microsoft.com/office/excel/2010/spreadsheetDrawing" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:dsp="http://schemas.microsoft.com/office/drawing/2008/diagram" xmlns:mso14="http://schemas.microsoft.com/office/2009/07/customui" xmlns:dgm14="http://schemas.microsoft.com/office/drawing/2010/diagram" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" xmlns:x12ac="http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac" xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xmlns:xr4="http://schemas.microsoft.com/office/spreadsheetml/2016/revision4" xmlns:xr5="http://schemas.microsoft.com/office/spreadsheetml/2016/revision5" xmlns:xr6="http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" xmlns:xr7="http://schemas.microsoft.com/office/spreadsheetml/2016/revision7" xmlns:xr8="http://schemas.microsoft.com/office/spreadsheetml/2016/revision8" xmlns:xr9="http://schemas.microsoft.com/office/spreadsheetml/2016/revision9" xmlns:xr10="http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" xmlns:xr11="http://schemas.microsoft.com/office/spreadsheetml/2016/revision11" xmlns:xr12="http://schemas.microsoft.com/office/spreadsheetml/2016/revision12" xmlns:xr13="http://schemas.microsoft.com/office/spreadsheetml/2016/revision13" xmlns:xr14="http://schemas.microsoft.com/office/spreadsheetml/2016/revision14" xmlns:xr15="http://schemas.microsoft.com/office/spreadsheetml/2016/revision15" xmlns:x16="http://schemas.microsoft.com/office/spreadsheetml/2014/11/main" xmlns:x16r2="http://schemas.microsoft.com/office/spreadsheetml/2015/02/main" mc:Ignorable="c14 cdr14 a14 pic14 x14 xdr14 x14ac dsp mso14 dgm14 x15 x12ac x15ac xr xr2 xr3 xr4 xr5 xr6 xr7 xr8 xr9 xr10 xr11 xr12 xr13 xr14 xr15 x15 x16 x16r2 mo mx mv o v" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xr:uid="{00000000-0001-0000-0000-000000000000}">` + +const templateRichValue = `` + +const templateRichStructure = `` + +const templateRichValuetypes = `` diff --git a/xmlMetaData.go b/xmlMetaData.go index 80c42e2dfb..88e5dc7140 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -44,7 +44,14 @@ type xlsxFutureMetadata struct { // a block of future metadata information. This is a location for storing // feature extension information. type xlsxFutureMetadataBlock struct { - ExtLst *xlsxInnerXML `xml:"extLst"` + ExtLst struct { + Ext struct { + URI string `xml:"uri,attr"` + Rvb struct { + I int `xml:"i,attr"` + } `xml:"rvb"` + } `xml:"ext"` + } `xml:"extLst"` } // xlsxMetadataBlocks directly maps the metadata element. This element From e62f2a2b413894e98f27e3349be983d9d6f1ecea Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Tue, 23 Apr 2024 17:07:35 +0500 Subject: [PATCH 12/28] feat: add spbdata structure --- excelize.go | 33 +++++++++++++++++++++++++++++---- xmlMetaData.go | 2 +- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/excelize.go b/excelize.go index 945b0d4c9d..f8077a6ec3 100644 --- a/excelize.go +++ b/excelize.go @@ -633,6 +633,15 @@ func (f *File) richDataSpbReader() (*XlsxRichDataSupportingPropertyBags, error) return &richDataspbs, nil } +func (f *File) richDataSpbStructureReader() (*xlsxRichDataSpbStructures, error) { + var richDataSpbStructure xlsxRichDataSpbStructures + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBagStructure)))). + Decode(&richDataSpbStructure); err != nil && err != io.EOF { + return &richDataSpbStructure, err + } + return &richDataSpbStructure, nil +} + func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { var richValue xlsxRichValueData if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). @@ -773,6 +782,11 @@ func (f *File) ReadEntity(sheet, cell string) (string, error) { return "", err } + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return "", err + } + for cellRichDataIdx, cellRichDataValue := range cellRichData.V { cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] @@ -804,22 +818,33 @@ func (f *File) ReadEntity(sheet, cell string) (string, error) { fmt.Println(boolValue) } else if cellRichStructure.T == "r" { fmt.Println("Value is of type formatted string or entity or image") + } else if cellRichStructure.T == "spb" { fmt.Println("Value is of type spb") // lots of work needed here - fmt.Println("SPB index is:") + // fmt.Println("SPB index is:") spbIndex, err := strconv.Atoi(cellRichDataValue) if err != nil { log.Fatal(err) } - fmt.Println(spbIndex) - fmt.Println("SPB value is:") - fmt.Println(richDataSpbs.SpbData.Spb[spbIndex]) + // fmt.Println(spbIndex) + // fmt.Println("SPB value is:") + // fmt.Println(richDataSpbs.SpbData.Spb[spbIndex]) if cellRichStructure.N == "_Provider" { fmt.Println("Footer data with text and logo:") fmt.Println(richDataSpbs.SpbData.Spb[spbIndex].V) // can there be multiple providers for one card? What about provider logo } + // fmt.Println("SPB structure value is:") + // fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S]) + + for spbDataValueIndex, spbDataValue := range richDataSpbs.SpbData.Spb[spbIndex].V { + fmt.Println("Spb data value is:") + fmt.Println(spbDataValue) + fmt.Println("Spb structure data is:") + fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S].K[spbDataValueIndex]) + } + } else if cellRichStructure.T == "a" { fmt.Println("Value is of type array") // array data was mapped. Can reuse code diff --git a/xmlMetaData.go b/xmlMetaData.go index 88e5dc7140..5788cdd546 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -174,7 +174,7 @@ type xlsxRichDataSpbData struct { // XlsxRichDataSpb directly maps the spb element that specifies data for a single supporting property bag. type xlsxRichDataSpb struct { Text string `xml:",chardata"` - S string `xml:"s,attr"` + S int `xml:"s,attr"` V []string `xml:"v"` } From f4a24de685455e7ed76e46d11c411957a025e01f Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Tue, 23 Apr 2024 17:30:37 +0500 Subject: [PATCH 13/28] fix: correct structure value --- excelize.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/excelize.go b/excelize.go index f8077a6ec3..61ab914ce5 100644 --- a/excelize.go +++ b/excelize.go @@ -834,15 +834,16 @@ func (f *File) ReadEntity(sheet, cell string) (string, error) { fmt.Println("Footer data with text and logo:") fmt.Println(richDataSpbs.SpbData.Spb[spbIndex].V) // can there be multiple providers for one card? What about provider logo - } - // fmt.Println("SPB structure value is:") - // fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S]) - - for spbDataValueIndex, spbDataValue := range richDataSpbs.SpbData.Spb[spbIndex].V { - fmt.Println("Spb data value is:") - fmt.Println(spbDataValue) - fmt.Println("Spb structure data is:") - fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S].K[spbDataValueIndex]) + } else { + // fmt.Println("SPB structure value is:") + // fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S]) + + for spbDataValueIndex, spbDataValue := range richDataSpbs.SpbData.Spb[spbIndex].V { + fmt.Println("Spb data value is:") + fmt.Println(spbDataValue) + fmt.Println("Spb structure data is:") + fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S].K[spbDataValueIndex].N) + } } } else if cellRichStructure.T == "a" { From 11a714df6e6954a5e4dc133afd21bbd64322fe74 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 12:25:15 +0500 Subject: [PATCH 14/28] feat: cleaning different data types --- excelize.go | 197 +++++++++++++++++++++++++++++----------------------- 1 file changed, 112 insertions(+), 85 deletions(-) diff --git a/excelize.go b/excelize.go index 61ab914ce5..557a2b72d0 100644 --- a/excelize.go +++ b/excelize.go @@ -759,104 +759,131 @@ func (f *File) ReadEntity(sheet, cell string) (string, error) { for _, row := range ws.SheetData.Row { for _, c := range row.C { if c.R == cell { + f.readCellEntity(c, metadata) + } + } + } + return "", err +} - cellMetadataIdx := *c.Vm - 1 - richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I - richValue, err := f.richValueReader() - if err != nil { - return "", err - } - if richValueIdx >= len(richValue.Rv) { - return "", err - } +func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (string, error) { - cellRichData := richValue.Rv[richValueIdx] + cellMetadataIdx := *c.Vm - 1 + richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I + richValue, err := f.richValueReader() + if err != nil { + return "", err + } + if richValueIdx >= len(richValue.Rv) { + return "", err + } - richValueStructure, err := f.richStructureReader() - if err != nil { - return "", err - } + cellRichData := richValue.Rv[richValueIdx] - richDataSpbs, err := f.richDataSpbReader() - if err != nil { - return "", err - } + richValueStructure, err := f.richStructureReader() + if err != nil { + return "", err + } - richDataSpbStructure, err := f.richDataSpbStructureReader() - if err != nil { - return "", err - } + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return "", err + } - for cellRichDataIdx, cellRichDataValue := range cellRichData.V { - cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] - - print("\n\n") - fmt.Println(cellRichStructure) - fmt.Println(cellRichDataValue) - - if cellRichStructure.T == "" { - fmt.Println("Key is:") - fmt.Println(cellRichStructure.N) - fmt.Println("Value is:") - fmt.Println(cellRichDataValue) - } else if cellRichStructure.T == "s" { - if cellRichStructure.N[0] == '_' { - fmt.Println("Value is richdata special formatted") - // more if else here - if cellRichStructure.N == "_DisplayString" { - fmt.Println("Outermost value which will be shown inside the cell") - } else if cellRichStructure.N == "_Icon" { - fmt.Println("Outermost icon which will be shown inside the cell") - } - } - } else if cellRichStructure.T == "b" { - fmt.Println("Value is boolean") // 1=true, 0=false - fmt.Println("Key is:") - fmt.Println(cellRichStructure.N) - fmt.Println("Value is:") - boolValue := cellRichDataValue == "1" - fmt.Println(boolValue) - } else if cellRichStructure.T == "r" { - fmt.Println("Value is of type formatted string or entity or image") - - } else if cellRichStructure.T == "spb" { - fmt.Println("Value is of type spb") - // lots of work needed here - // fmt.Println("SPB index is:") - spbIndex, err := strconv.Atoi(cellRichDataValue) - if err != nil { - log.Fatal(err) - } - // fmt.Println(spbIndex) - // fmt.Println("SPB value is:") - // fmt.Println(richDataSpbs.SpbData.Spb[spbIndex]) - if cellRichStructure.N == "_Provider" { - fmt.Println("Footer data with text and logo:") - fmt.Println(richDataSpbs.SpbData.Spb[spbIndex].V) - // can there be multiple providers for one card? What about provider logo - } else { - // fmt.Println("SPB structure value is:") - // fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S]) - - for spbDataValueIndex, spbDataValue := range richDataSpbs.SpbData.Spb[spbIndex].V { - fmt.Println("Spb data value is:") - fmt.Println(spbDataValue) - fmt.Println("Spb structure data is:") - fmt.Println(richDataSpbStructure.S[richDataSpbs.SpbData.Spb[spbIndex].S].K[spbDataValueIndex].N) - } - } - - } else if cellRichStructure.T == "a" { - fmt.Println("Value is of type array") - // array data was mapped. Can reuse code - } + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return "", err + } + + entityMap := make(map[string]any) + stringValueMap := make(map[string]string) + + for cellRichDataIdx, cellRichDataValue := range cellRichData.V { + cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] + + print("\n\n") + fmt.Println(cellRichStructure) + fmt.Println(cellRichDataValue) + + if cellRichStructure.T == "" { + entityMap[cellRichStructure.N] = cellRichDataValue + } else if cellRichStructure.T == "b" { + boolValue := cellRichDataValue == "1" + entityMap[cellRichStructure.N] = boolValue + } else if cellRichStructure.T == "s" { + processStringType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue) + + } else if cellRichStructure.T == "r" { + err := processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) + if err != nil { + return "", err + } + + } else if cellRichStructure.T == "spb" { + fmt.Println("Value is of type spb") + spbIndex, err := strconv.Atoi(cellRichDataValue) + if err != nil { + log.Fatal(err) + } + if cellRichStructure.N == "_Provider" { + entityMap["Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] + // can there be multiple providers for one card? What about provider logo + } else if cellRichStructure.N == "_Display" { + displayData := richDataSpbs.SpbData.Spb[spbIndex] + for spbDataValueIndex, spbDataValue := range displayData.V { + fmt.Println("Spb data value is:") + fmt.Println(spbDataValue) + fmt.Println("Spb structure data is:") + fmt.Println(richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N) + entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = stringValueMap[spbDataValue] } } } } + fmt.Println(entityMap) return "", err } +func processStringType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { + if cellRichStructure.N[0] == '_' { + if cellRichStructure.N == "_DisplayString" { + entityMap["Display String"] = cellRichDataValue + } else if cellRichStructure.N == "_Icon" { + entityMap["Icon"] = cellRichDataValue + } + } else { + stringValueMap[cellRichStructure.N] = cellRichDataValue + fmt.Println("Value is normal string") + fmt.Println("Key is:") + fmt.Println(cellRichStructure.N) + fmt.Println("Value is:") + fmt.Println(cellRichDataValue) + } +} + +func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { + fmt.Println("Value is of type formatted string or entity or array") + fmt.Println("Key is:") + fmt.Println(cellRichStructure.N) + entityMap[cellRichStructure.N] = "Value is of type formatted string or entity or array" + fmt.Println("Rich Value index is:") + fmt.Println(cellRichDataValue) + + cellRichDataValueInt, err := strconv.Atoi(cellRichDataValue) + if err != nil { + return err // Return the error instead of using log.Fatal to allow the caller to handle it + } + + if cellRichDataValueInt < 0 || cellRichDataValueInt >= len(richValue.Rv) { + return fmt.Errorf("index out of range: %d", cellRichDataValueInt) + } + + subRichData := richValue.Rv[cellRichDataValueInt] + _ = subRichData + // processing remaining + return nil +} + // richValueRelReader provides a function to get the pointer to the structure // after deserialization of xl/richData/richValueRel.xml. func (f *File) richValueRelReader() (*xlsxRichValueRels, error) { From 9ab21b4f679b10a465a27e08406624daf44cfd58 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 12:30:07 +0500 Subject: [PATCH 15/28] feat: return correct type --- excelize.go | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/excelize.go b/excelize.go index 557a2b72d0..eb57b1fe01 100644 --- a/excelize.go +++ b/excelize.go @@ -737,19 +737,20 @@ func (f *File) AddEntity(sheet, cell, entityData string) { // marshal the entity data and store inside files accordingly } -func (f *File) ReadEntity(sheet, cell string) (string, error) { +func (f *File) ReadEntity(sheet, cell string) (map[string]any, error) { + entityMap := make(map[string]any) cellType, err := f.GetCellType(sheet, cell) if err != nil { - return "", err + return entityMap, err } if cellType != 3 { - return "", errors.New("Cell is not of type entity") + return entityMap, errors.New("Cell is not of type entity") } metadata, err := f.metadataReader() if err != nil { - return "", err + return entityMap, err } ws, _ := f.workSheetReader(sheet) @@ -759,45 +760,46 @@ func (f *File) ReadEntity(sheet, cell string) (string, error) { for _, row := range ws.SheetData.Row { for _, c := range row.C { if c.R == cell { - f.readCellEntity(c, metadata) + entityMap, err := f.readCellEntity(c, metadata) + return entityMap, err } } } - return "", err + return entityMap, err } -func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (string, error) { +func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, error) { + + entityMap := make(map[string]any) + stringValueMap := make(map[string]string) cellMetadataIdx := *c.Vm - 1 richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I richValue, err := f.richValueReader() if err != nil { - return "", err + return entityMap, err } if richValueIdx >= len(richValue.Rv) { - return "", err + return entityMap, err } cellRichData := richValue.Rv[richValueIdx] richValueStructure, err := f.richStructureReader() if err != nil { - return "", err + return entityMap, err } richDataSpbs, err := f.richDataSpbReader() if err != nil { - return "", err + return entityMap, err } richDataSpbStructure, err := f.richDataSpbStructureReader() if err != nil { - return "", err + return entityMap, err } - entityMap := make(map[string]any) - stringValueMap := make(map[string]string) - for cellRichDataIdx, cellRichDataValue := range cellRichData.V { cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] @@ -816,7 +818,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (string, error) { } else if cellRichStructure.T == "r" { err := processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) if err != nil { - return "", err + return entityMap, err } } else if cellRichStructure.T == "spb" { @@ -840,8 +842,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (string, error) { } } } - fmt.Println(entityMap) - return "", err + return entityMap, err } func processStringType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { From 38d8d5a07489d8e0882defba4fdb0e6628b0e0a3 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 14:33:24 +0500 Subject: [PATCH 16/28] feat: clean spb processing --- excelize.go | 54 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/excelize.go b/excelize.go index eb57b1fe01..ec35ddcab4 100644 --- a/excelize.go +++ b/excelize.go @@ -19,7 +19,6 @@ import ( "errors" "fmt" "io" - "log" "os" "path/filepath" "strconv" @@ -822,27 +821,14 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, } } else if cellRichStructure.T == "spb" { - fmt.Println("Value is of type spb") - spbIndex, err := strconv.Atoi(cellRichDataValue) + err := processSpbType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue, richDataSpbs, richDataSpbStructure) if err != nil { - log.Fatal(err) - } - if cellRichStructure.N == "_Provider" { - entityMap["Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] - // can there be multiple providers for one card? What about provider logo - } else if cellRichStructure.N == "_Display" { - displayData := richDataSpbs.SpbData.Spb[spbIndex] - for spbDataValueIndex, spbDataValue := range displayData.V { - fmt.Println("Spb data value is:") - fmt.Println(spbDataValue) - fmt.Println("Spb structure data is:") - fmt.Println(richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N) - entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = stringValueMap[spbDataValue] - } + return entityMap, err // Handle the error appropriately } } } - return entityMap, err + fmt.Println(stringValueMap) + return entityMap, nil } func processStringType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { @@ -872,7 +858,7 @@ func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueSt cellRichDataValueInt, err := strconv.Atoi(cellRichDataValue) if err != nil { - return err // Return the error instead of using log.Fatal to allow the caller to handle it + return err } if cellRichDataValueInt < 0 || cellRichDataValueInt >= len(richValue.Rv) { @@ -880,11 +866,41 @@ func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueSt } subRichData := richValue.Rv[cellRichDataValueInt] + if subRichData.Fb != "" { + entityMap[cellRichStructure.N] = subRichData.Fb + } _ = subRichData // processing remaining return nil } +func processSpbType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richDataSpbs *XlsxRichDataSupportingPropertyBags, richDataSpbStructure *xlsxRichDataSpbStructures) error { + fmt.Println("Value is of type spb") + spbIndex, err := strconv.Atoi(cellRichDataValue) + if err != nil { + return err // Return the error instead of using log.Fatal + } + + if spbIndex < 0 || spbIndex >= len(richDataSpbs.SpbData.Spb) { + return fmt.Errorf("index out of range: %d", spbIndex) + } + + if cellRichStructure.N == "_Provider" { + entityMap["Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] + // Handle multiple providers or provider logo if necessary + } else if cellRichStructure.N == "_Display" { + displayData := richDataSpbs.SpbData.Spb[spbIndex] + for spbDataValueIndex, spbDataValue := range displayData.V { + fmt.Println("Spb data value is:") + fmt.Println(spbDataValue) + fmt.Println("Spb structure data is:") + fmt.Println(richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N) + entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = stringValueMap[spbDataValue] + } + } + return nil // Return nil if no error occurred +} + // richValueRelReader provides a function to get the pointer to the structure // after deserialization of xl/richData/richValueRel.xml. func (f *File) richValueRelReader() (*xlsxRichValueRels, error) { From bd1c3dc19e0e86e48b2e61a747247b5e4c0b825d Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 14:34:36 +0500 Subject: [PATCH 17/28] fix: remove not needed comments --- excelize.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/excelize.go b/excelize.go index ec35ddcab4..dd0714aa1c 100644 --- a/excelize.go +++ b/excelize.go @@ -823,7 +823,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, } else if cellRichStructure.T == "spb" { err := processSpbType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue, richDataSpbs, richDataSpbStructure) if err != nil { - return entityMap, err // Handle the error appropriately + return entityMap, err } } } @@ -878,7 +878,7 @@ func processSpbType(entityMap map[string]any, stringValueMap map[string]string, fmt.Println("Value is of type spb") spbIndex, err := strconv.Atoi(cellRichDataValue) if err != nil { - return err // Return the error instead of using log.Fatal + return err } if spbIndex < 0 || spbIndex >= len(richDataSpbs.SpbData.Spb) { @@ -898,7 +898,7 @@ func processSpbType(entityMap map[string]any, stringValueMap map[string]string, entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = stringValueMap[spbDataValue] } } - return nil // Return nil if no error occurred + return nil } // richValueRelReader provides a function to get the pointer to the structure From b8e63c4ebd274c53b90d2da86596a0780a904a47 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 14:46:49 +0500 Subject: [PATCH 18/28] fix: seperate spb reader --- excelize.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/excelize.go b/excelize.go index dd0714aa1c..f18086a66a 100644 --- a/excelize.go +++ b/excelize.go @@ -789,16 +789,6 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, return entityMap, err } - richDataSpbs, err := f.richDataSpbReader() - if err != nil { - return entityMap, err - } - - richDataSpbStructure, err := f.richDataSpbStructureReader() - if err != nil { - return entityMap, err - } - for cellRichDataIdx, cellRichDataValue := range cellRichData.V { cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] @@ -821,7 +811,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, } } else if cellRichStructure.T == "spb" { - err := processSpbType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue, richDataSpbs, richDataSpbStructure) + err := f.processSpbType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue) if err != nil { return entityMap, err } @@ -874,7 +864,16 @@ func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueSt return nil } -func processSpbType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richDataSpbs *XlsxRichDataSupportingPropertyBags, richDataSpbStructure *xlsxRichDataSpbStructures) error { +func (f *File) processSpbType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return err + } + + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return err + } fmt.Println("Value is of type spb") spbIndex, err := strconv.Atoi(cellRichDataValue) if err != nil { From 8a0a7dc5a7be36c125e182036d4bd9f8f51222bc Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 15:26:45 +0500 Subject: [PATCH 19/28] fix: string value map use remove for now --- excelize.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/excelize.go b/excelize.go index f18086a66a..e4538cf8d3 100644 --- a/excelize.go +++ b/excelize.go @@ -811,7 +811,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, } } else if cellRichStructure.T == "spb" { - err := f.processSpbType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue) + err := f.processSpbType(entityMap, cellRichStructure, cellRichDataValue) if err != nil { return entityMap, err } @@ -864,7 +864,7 @@ func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueSt return nil } -func (f *File) processSpbType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { +func (f *File) processSpbType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { richDataSpbs, err := f.richDataSpbReader() if err != nil { return err @@ -894,7 +894,7 @@ func (f *File) processSpbType(entityMap map[string]any, stringValueMap map[strin fmt.Println(spbDataValue) fmt.Println("Spb structure data is:") fmt.Println(richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N) - entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = stringValueMap[spbDataValue] + entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = spbDataValue } } return nil From cfd3f0220593837f95e92340e44ceac220da9595 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 16:51:58 +0500 Subject: [PATCH 20/28] feat: parsing of sub rich data entity --- excelize.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/excelize.go b/excelize.go index e4538cf8d3..1a0cf964b0 100644 --- a/excelize.go +++ b/excelize.go @@ -805,7 +805,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, processStringType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue) } else if cellRichStructure.T == "r" { - err := processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) + err := f.processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) if err != nil { return entityMap, err } @@ -838,7 +838,7 @@ func processStringType(entityMap map[string]any, stringValueMap map[string]strin } } -func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { +func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { fmt.Println("Value is of type formatted string or entity or array") fmt.Println("Key is:") fmt.Println(cellRichStructure.N) @@ -858,6 +858,27 @@ func processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueSt subRichData := richValue.Rv[cellRichDataValueInt] if subRichData.Fb != "" { entityMap[cellRichStructure.N] = subRichData.Fb + } else { + richValueStructure, err := f.richStructureReader() + if err != nil { + return err + } + subRichStructure := richValueStructure.S[subRichData.S] + fmt.Println("Sub rich data:") + fmt.Println(subRichData) + fmt.Println("Sub rich structure") + fmt.Println(subRichStructure) + + if subRichStructure.T == "_entity" { + subRichEntityMap := make(map[string]any) + for subRichDataValueIdx, subRichDatavalue := range subRichData.V { + subRichDataStructure := subRichStructure.K[subRichDataValueIdx].N + subRichEntityMap[subRichDataStructure] = subRichDatavalue + } + entityMap[cellRichStructure.N] = subRichEntityMap + } else if subRichStructure.T == "_array" { + + } } _ = subRichData // processing remaining From 766f94a052ed3ef877cd8bd01c9fb5f7bd4d4042 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Wed, 24 Apr 2024 17:20:08 +0500 Subject: [PATCH 21/28] fix: create path if does not exist --- excelize.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/excelize.go b/excelize.go index 1a0cf964b0..a7fb71568e 100644 --- a/excelize.go +++ b/excelize.go @@ -717,10 +717,15 @@ func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { // return nil // } -func (f *File) CheckOrCreateRichData() { +func (f *File) CheckOrCreateRichData() error { + dirPath := filepath.Join(f.Path, "xl", "richData") + if err := os.MkdirAll(dirPath, os.ModePerm); err != nil { + return fmt.Errorf("failed to create directory: %v", err) + } f.CheckOrCreateXML(defaultXMLRdRichValuePart, []byte(xml.Header+templateRichValue)) f.CheckOrCreateXML(defaultXMLRichDataRichValueStructure, []byte(xml.Header+templateRichStructure)) f.CheckOrCreateXML(defaultXMLRichDataRichValueTypes, []byte(xml.Header+templateRichValuetypes)) + return nil } func (f *File) CheckOrCreateXML(name string, defaultContent []byte) { From 6b9dd33c8136e084ca5d1431f4449312d0ad1104 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Thu, 25 Apr 2024 12:43:40 +0500 Subject: [PATCH 22/28] feat: read array data done --- excelize.go | 50 ++++++++++++++++++++++++++++++++++++++++++++------ xmlMetaData.go | 10 +++++----- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/excelize.go b/excelize.go index a7fb71568e..0125c3feda 100644 --- a/excelize.go +++ b/excelize.go @@ -641,6 +641,15 @@ func (f *File) richDataSpbStructureReader() (*xlsxRichDataSpbStructures, error) return &richDataSpbStructure, nil } +func (f *File) richDataArrayReader() (*xlsxRichValueArrayData, error) { + var richDataArray xlsxRichValueArrayData + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataArray)))). + Decode(&richDataArray); err != nil && err != io.EOF { + return &richDataArray, err + } + return &richDataArray, nil +} + func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { var richValue xlsxRichValueData if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). @@ -729,9 +738,7 @@ func (f *File) CheckOrCreateRichData() error { } func (f *File) CheckOrCreateXML(name string, defaultContent []byte) { - // Check if the XML file exists if _, ok := f.Pkg.Load(name); !ok { - // The XML file does not exist, so create it with the default content f.Pkg.Store(name, defaultContent) } } @@ -829,9 +836,9 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, func processStringType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { if cellRichStructure.N[0] == '_' { if cellRichStructure.N == "_DisplayString" { - entityMap["Display String"] = cellRichDataValue + entityMap["_DisplayString"] = cellRichDataValue } else if cellRichStructure.N == "_Icon" { - entityMap["Icon"] = cellRichDataValue + entityMap["_Icon"] = cellRichDataValue } } else { stringValueMap[cellRichStructure.N] = cellRichDataValue @@ -882,7 +889,39 @@ func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxR } entityMap[cellRichStructure.N] = subRichEntityMap } else if subRichStructure.T == "_array" { + richDataArray, err := f.richDataArrayReader() + if err != nil { + return err + } + for subRichStructureIdx, _ := range subRichStructure.K { + colCount := richDataArray.A[subRichStructureIdx].C + rows := make([][]interface{}, 0) + row := make([]interface{}, 0, colCount) + for richDataArrayValueIdx, richDataArrayValue := range richDataArray.A[subRichStructureIdx].V { + if richDataArrayValue.T == "s" { + row = append(row, richDataArrayValue.Text) + } else if richDataArrayValue.T == "r" { + arrayValueRichValueIdx, err := strconv.Atoi(richDataArrayValue.Text) + if err != nil { + return err + } + arrayValueRichValue := richValue.Rv[arrayValueRichValueIdx] + if arrayValueRichValue.Fb != "" { + unformattedValue := arrayValueRichValue.Fb + row = append(row, unformattedValue) + } + } + if (richDataArrayValueIdx+1)%colCount == 0 { + rows = append(rows, row) + row = make([]interface{}, 0, colCount) + } + } + if len(row) > 0 { + rows = append(rows, row) + } + entityMap[cellRichStructure.N] = rows + } } } _ = subRichData @@ -911,8 +950,7 @@ func (f *File) processSpbType(entityMap map[string]any, cellRichStructure xlsxRi } if cellRichStructure.N == "_Provider" { - entityMap["Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] - // Handle multiple providers or provider logo if necessary + entityMap["_Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] } else if cellRichStructure.N == "_Display" { displayData := richDataSpbs.SpbData.Spb[spbIndex] for spbDataValueIndex, spbDataValue := range displayData.V { diff --git a/xmlMetaData.go b/xmlMetaData.go index 5788cdd546..ac8f145a20 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -78,17 +78,17 @@ type xlsxMetadataRecord struct { // xlsxRichValueArrayData directly maps the arrayData element that specifies rich value // arrays. type xlsxRichValueArrayData struct { - XMLName xml.Name `xml:"arrayData"` - Xmlns string `xml:"xmlns,attr"` - Count string `xml:"count,attr"` - A xlsxRichValuesArray `xml:"a"` + XMLName xml.Name `xml:"arrayData"` + Xmlns string `xml:"xmlns,attr"` + Count string `xml:"count,attr"` + A []xlsxRichValuesArray `xml:"a"` } // xlsxRichValuesArray directly maps the a element that specifies rich values Array // information for an array data type xlsxRichValuesArray struct { R string `xml:"r,attr"` - C string `xml:"c,attr"` + C int `xml:"c,attr"` V []xlsxRichArrayValue `xml:"v"` } From 76080e70abcf8c6a17d94d50cb450d61a6e65166 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Thu, 25 Apr 2024 14:07:37 +0500 Subject: [PATCH 23/28] fix: remove unneeded prints --- excelize.go | 83 +++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/excelize.go b/excelize.go index 0125c3feda..9333965eda 100644 --- a/excelize.go +++ b/excelize.go @@ -805,8 +805,6 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] print("\n\n") - fmt.Println(cellRichStructure) - fmt.Println(cellRichDataValue) if cellRichStructure.T == "" { entityMap[cellRichStructure.N] = cellRichDataValue @@ -851,12 +849,6 @@ func processStringType(entityMap map[string]any, stringValueMap map[string]strin } func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { - fmt.Println("Value is of type formatted string or entity or array") - fmt.Println("Key is:") - fmt.Println(cellRichStructure.N) - entityMap[cellRichStructure.N] = "Value is of type formatted string or entity or array" - fmt.Println("Rich Value index is:") - fmt.Println(cellRichDataValue) cellRichDataValueInt, err := strconv.Atoi(cellRichDataValue) if err != nil { @@ -876,11 +868,6 @@ func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxR return err } subRichStructure := richValueStructure.S[subRichData.S] - fmt.Println("Sub rich data:") - fmt.Println(subRichData) - fmt.Println("Sub rich structure") - fmt.Println(subRichStructure) - if subRichStructure.T == "_entity" { subRichEntityMap := make(map[string]any) for subRichDataValueIdx, subRichDatavalue := range subRichData.V { @@ -889,46 +876,53 @@ func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxR } entityMap[cellRichStructure.N] = subRichEntityMap } else if subRichStructure.T == "_array" { - richDataArray, err := f.richDataArrayReader() + err := f.processRichDataArrayType(entityMap, cellRichStructure, subRichStructure, richValue) if err != nil { return err } - for subRichStructureIdx, _ := range subRichStructure.K { - colCount := richDataArray.A[subRichStructureIdx].C - rows := make([][]interface{}, 0) - row := make([]interface{}, 0, colCount) - for richDataArrayValueIdx, richDataArrayValue := range richDataArray.A[subRichStructureIdx].V { - if richDataArrayValue.T == "s" { - row = append(row, richDataArrayValue.Text) - } else if richDataArrayValue.T == "r" { - arrayValueRichValueIdx, err := strconv.Atoi(richDataArrayValue.Text) - if err != nil { - return err - } - arrayValueRichValue := richValue.Rv[arrayValueRichValueIdx] - if arrayValueRichValue.Fb != "" { - unformattedValue := arrayValueRichValue.Fb - row = append(row, unformattedValue) - } + } + } + return nil +} +func (f *File) processRichDataArrayType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, subRichStructure xlsxRichValueStructure, richValue *xlsxRichValueData) error { + richDataArray, err := f.richDataArrayReader() + if err != nil { + return err + } - } - if (richDataArrayValueIdx+1)%colCount == 0 { - rows = append(rows, row) - row = make([]interface{}, 0, colCount) - } + for subRichStructureIdx := range subRichStructure.K { + colCount := richDataArray.A[subRichStructureIdx].C + rows := make([][]interface{}, 0) + row := make([]interface{}, 0, colCount) + for richDataArrayValueIdx, richDataArrayValue := range richDataArray.A[subRichStructureIdx].V { + if richDataArrayValue.T == "s" { + row = append(row, richDataArrayValue.Text) + } else if richDataArrayValue.T == "r" { + arrayValueRichValueIdx, err := strconv.Atoi(richDataArrayValue.Text) + if err != nil { + return err + } + if arrayValueRichValueIdx < 0 || arrayValueRichValueIdx >= len(richValue.Rv) { + return fmt.Errorf("index out of range: %d", arrayValueRichValueIdx) } - if len(row) > 0 { - rows = append(rows, row) + arrayValueRichValue := richValue.Rv[arrayValueRichValueIdx] + if arrayValueRichValue.Fb != "" { + unformattedValue := arrayValueRichValue.Fb + row = append(row, unformattedValue) } - entityMap[cellRichStructure.N] = rows } + if (richDataArrayValueIdx+1)%colCount == 0 { + rows = append(rows, row) + row = make([]interface{}, 0, colCount) + } + } + if len(row) > 0 { + rows = append(rows, row) } + entityMap[cellRichStructure.N] = rows } - _ = subRichData - // processing remaining return nil } - func (f *File) processSpbType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { richDataSpbs, err := f.richDataSpbReader() if err != nil { @@ -939,7 +933,6 @@ func (f *File) processSpbType(entityMap map[string]any, cellRichStructure xlsxRi if err != nil { return err } - fmt.Println("Value is of type spb") spbIndex, err := strconv.Atoi(cellRichDataValue) if err != nil { return err @@ -954,10 +947,6 @@ func (f *File) processSpbType(entityMap map[string]any, cellRichStructure xlsxRi } else if cellRichStructure.N == "_Display" { displayData := richDataSpbs.SpbData.Spb[spbIndex] for spbDataValueIndex, spbDataValue := range displayData.V { - fmt.Println("Spb data value is:") - fmt.Println(spbDataValue) - fmt.Println("Spb structure data is:") - fmt.Println(richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N) entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = spbDataValue } } From 83df17e704cf6fee09504bc15f11c62eebd5029b Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Thu, 25 Apr 2024 14:50:50 +0500 Subject: [PATCH 24/28] fix: function name --- excelize.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/excelize.go b/excelize.go index 9333965eda..8184651e4e 100644 --- a/excelize.go +++ b/excelize.go @@ -726,7 +726,7 @@ func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { // return nil // } -func (f *File) CheckOrCreateRichData() error { +func (f *File) CheckOrCreateRichDataFiles() error { dirPath := filepath.Join(f.Path, "xl", "richData") if err := os.MkdirAll(dirPath, os.ModePerm); err != nil { return fmt.Errorf("failed to create directory: %v", err) @@ -744,7 +744,7 @@ func (f *File) CheckOrCreateXML(name string, defaultContent []byte) { } func (f *File) AddEntity(sheet, cell, entityData string) { - f.CheckOrCreateRichData() + f.CheckOrCreateRichDataFiles() // marshal the entity data and store inside files accordingly } From 6415c6387ba4f6e7b399eaaf8aaf3750568380ba Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Thu, 25 Apr 2024 17:17:47 +0500 Subject: [PATCH 25/28] fix: naming convention package --- excelize.go | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/excelize.go b/excelize.go index 8184651e4e..d1d158edad 100644 --- a/excelize.go +++ b/excelize.go @@ -743,14 +743,29 @@ func (f *File) CheckOrCreateXML(name string, defaultContent []byte) { } } -func (f *File) AddEntity(sheet, cell, entityData string) { +func (f *File) AddEntity(sheet, cell string, entityData map[string]interface{}) error { f.CheckOrCreateRichDataFiles() + ws, err := f.workSheetReader(sheet) + if err != nil { + return err + } + ws.mu.Lock() + defer ws.mu.Unlock() + for _, row := range ws.SheetData.Row { + for _, c := range row.C { + if c.R == cell { + err := f.writeCellEntity(cell, entityData) + return err + } + } + } // marshal the entity data and store inside files accordingly + return nil } -func (f *File) ReadEntity(sheet, cell string) (map[string]any, error) { +func (f *File) ReadEntity(sheet, cell string) (map[string]interface{}, error) { - entityMap := make(map[string]any) + entityMap := make(map[string]interface{}) cellType, err := f.GetCellType(sheet, cell) if err != nil { return entityMap, err @@ -779,9 +794,9 @@ func (f *File) ReadEntity(sheet, cell string) (map[string]any, error) { return entityMap, err } -func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, error) { +func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]interface{}, error) { - entityMap := make(map[string]any) + entityMap := make(map[string]interface{}) stringValueMap := make(map[string]string) cellMetadataIdx := *c.Vm - 1 @@ -804,8 +819,6 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, for cellRichDataIdx, cellRichDataValue := range cellRichData.V { cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] - print("\n\n") - if cellRichStructure.T == "" { entityMap[cellRichStructure.N] = cellRichDataValue } else if cellRichStructure.T == "b" { @@ -831,7 +844,7 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]any, return entityMap, nil } -func processStringType(entityMap map[string]any, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { +func processStringType(entityMap map[string]interface{}, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { if cellRichStructure.N[0] == '_' { if cellRichStructure.N == "_DisplayString" { entityMap["_DisplayString"] = cellRichDataValue @@ -848,7 +861,7 @@ func processStringType(entityMap map[string]any, stringValueMap map[string]strin } } -func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { +func (f *File) processRichType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { cellRichDataValueInt, err := strconv.Atoi(cellRichDataValue) if err != nil { @@ -869,7 +882,7 @@ func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxR } subRichStructure := richValueStructure.S[subRichData.S] if subRichStructure.T == "_entity" { - subRichEntityMap := make(map[string]any) + subRichEntityMap := make(map[string]interface{}) for subRichDataValueIdx, subRichDatavalue := range subRichData.V { subRichDataStructure := subRichStructure.K[subRichDataValueIdx].N subRichEntityMap[subRichDataStructure] = subRichDatavalue @@ -884,7 +897,7 @@ func (f *File) processRichType(entityMap map[string]any, cellRichStructure xlsxR } return nil } -func (f *File) processRichDataArrayType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, subRichStructure xlsxRichValueStructure, richValue *xlsxRichValueData) error { +func (f *File) processRichDataArrayType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, subRichStructure xlsxRichValueStructure, richValue *xlsxRichValueData) error { richDataArray, err := f.richDataArrayReader() if err != nil { return err @@ -923,7 +936,7 @@ func (f *File) processRichDataArrayType(entityMap map[string]any, cellRichStruct } return nil } -func (f *File) processSpbType(entityMap map[string]any, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { +func (f *File) processSpbType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { richDataSpbs, err := f.richDataSpbReader() if err != nil { return err From 272cad28683345f4a4407d4c8c04af373bc45371 Mon Sep 17 00:00:00 2001 From: Hamza Anis Date: Fri, 26 Apr 2024 13:08:40 +0500 Subject: [PATCH 26/28] fix: use json struct instead of map --- excelize.go | 83 +++++++++++++++++++++++++++++++++++--------------- xmlMetaData.go | 2 +- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/excelize.go b/excelize.go index d1d158edad..f7dbbeff12 100644 --- a/excelize.go +++ b/excelize.go @@ -15,6 +15,7 @@ package excelize import ( "archive/zip" "bytes" + "encoding/json" "encoding/xml" "errors" "fmt" @@ -61,6 +62,24 @@ type File struct { WorkBook *xlsxWorkbook } +type Entity struct { + Type string `json:"type"` + Text string `json:"text"` + Layouts struct { + Compact struct { + Icon string `json:"icon"` + } `json:"compact"` + Card struct { + Title struct { + Property string `json:"property"` + } `json:"title"` + SubTitle struct { + Property string `json:"property"` + } `json:"subTitle"` + } `json:"card"` + } `json:"layouts"` +} + // charsetTranscoderFn set user-defined codepage transcoder function for open // the spreadsheet from non-UTF-8 encoding. type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, err error) @@ -726,25 +745,25 @@ func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { // return nil // } -func (f *File) CheckOrCreateRichDataFiles() error { +func (f *File) checkOrCreateRichDataFiles() error { dirPath := filepath.Join(f.Path, "xl", "richData") if err := os.MkdirAll(dirPath, os.ModePerm); err != nil { return fmt.Errorf("failed to create directory: %v", err) } - f.CheckOrCreateXML(defaultXMLRdRichValuePart, []byte(xml.Header+templateRichValue)) - f.CheckOrCreateXML(defaultXMLRichDataRichValueStructure, []byte(xml.Header+templateRichStructure)) - f.CheckOrCreateXML(defaultXMLRichDataRichValueTypes, []byte(xml.Header+templateRichValuetypes)) + f.checkOrCreateXML(defaultXMLRdRichValuePart, []byte(xml.Header+templateRichValue)) + f.checkOrCreateXML(defaultXMLRichDataRichValueStructure, []byte(xml.Header+templateRichStructure)) + f.checkOrCreateXML(defaultXMLRichDataRichValueTypes, []byte(xml.Header+templateRichValuetypes)) return nil } -func (f *File) CheckOrCreateXML(name string, defaultContent []byte) { +func (f *File) checkOrCreateXML(name string, defaultContent []byte) { if _, ok := f.Pkg.Load(name); !ok { f.Pkg.Store(name, defaultContent) } } -func (f *File) AddEntity(sheet, cell string, entityData map[string]interface{}) error { - f.CheckOrCreateRichDataFiles() +func (f *File) AddEntity(sheet, cell string, entityData []byte) error { + f.checkOrCreateRichDataFiles() ws, err := f.workSheetReader(sheet) if err != nil { return err @@ -759,42 +778,52 @@ func (f *File) AddEntity(sheet, cell string, entityData map[string]interface{}) } } } - // marshal the entity data and store inside files accordingly return nil } -func (f *File) ReadEntity(sheet, cell string) (map[string]interface{}, error) { +func (f *File) writeCellEntity(cell string, entity []byte) error { + return nil +} + +func (f *File) ReadEntity(sheet, cell string) ([]byte, error) { - entityMap := make(map[string]interface{}) cellType, err := f.GetCellType(sheet, cell) if err != nil { - return entityMap, err + return nil, err } if cellType != 3 { - return entityMap, errors.New("Cell is not of type entity") + return nil, errors.New("Cell is not of type entity") } metadata, err := f.metadataReader() if err != nil { - return entityMap, err + return nil, err } ws, _ := f.workSheetReader(sheet) ws.mu.Lock() defer ws.mu.Unlock() - + entityStruct := Entity{} for _, row := range ws.SheetData.Row { for _, c := range row.C { if c.R == cell { - entityMap, err := f.readCellEntity(c, metadata) - return entityMap, err + err = f.readCellEntity(c, metadata, &entityStruct) + if err != nil { + return nil, err + } + entityJSON, err := json.Marshal(entityStruct) + if err != nil { + return nil, err + } + return entityJSON, nil + } } } - return entityMap, err + return nil, nil } -func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]interface{}, error) { +func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata, entity *Entity) error { entityMap := make(map[string]interface{}) stringValueMap := make(map[string]string) @@ -803,17 +832,17 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]inter richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I richValue, err := f.richValueReader() if err != nil { - return entityMap, err + return err } if richValueIdx >= len(richValue.Rv) { - return entityMap, err + return err } cellRichData := richValue.Rv[richValueIdx] richValueStructure, err := f.richStructureReader() if err != nil { - return entityMap, err + return err } for cellRichDataIdx, cellRichDataValue := range cellRichData.V { @@ -830,18 +859,24 @@ func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (map[string]inter } else if cellRichStructure.T == "r" { err := f.processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) if err != nil { - return entityMap, err + return err } } else if cellRichStructure.T == "spb" { err := f.processSpbType(entityMap, cellRichStructure, cellRichDataValue) if err != nil { - return entityMap, err + return err } } } fmt.Println(stringValueMap) - return entityMap, nil + fmt.Println(entityMap) + entity.Text = entityMap["_DisplayString"].(string) + entity.Layouts.Compact.Icon = entityMap["_Icon"].(string) + entity.Layouts.Card.Title.Property = entityMap["TitleProperty"].(string) + entity.Layouts.Card.SubTitle.Property = entityMap["SubTitleProperty"].(string) + + return nil } func processStringType(entityMap map[string]interface{}, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { diff --git a/xmlMetaData.go b/xmlMetaData.go index ac8f145a20..dc0ed1c8d4 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -113,7 +113,7 @@ type xlsxRichValueData struct { type xlsxRichValue struct { S int `xml:"s,attr"` V []string `xml:"v"` - Fb string `xml:"fb"` + Fb string `xml:"fb,omitempty"` } // xlsxRichValueRels directly maps the richValueRels element. This element that From da95e4f30a7c3e07de64a61ac18fa43dad1c7090 Mon Sep 17 00:00:00 2001 From: hamzaanis Date: Tue, 14 May 2024 20:02:39 +0500 Subject: [PATCH 27/28] feat: partial array rich data, providers and titles working --- .gitignore | 1 + entity_read.go | 237 +++++++++++++++++++++ entity_write.go | 483 +++++++++++++++++++++++++++++++++++++++++++ excelize.go | 375 ++++----------------------------- excelize_test.go | 144 +++++++++++++ rich_data_test.go | 19 -- templates.go | 18 +- test/testEntity.json | 35 ++++ xmlMetaData.go | 80 ++++--- 9 files changed, 1011 insertions(+), 381 deletions(-) create mode 100644 entity_read.go create mode 100644 entity_write.go delete mode 100644 rich_data_test.go create mode 100644 test/testEntity.json diff --git a/.gitignore b/.gitignore index 8bf9e7f5b2..b554b317ad 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ test/Test*.xlsm test/Test*.xlsx test/Test*.xltm test/Test*.xltx +!test/testEntity.json \ No newline at end of file diff --git a/entity_read.go b/entity_read.go new file mode 100644 index 0000000000..4877f9118f --- /dev/null +++ b/entity_read.go @@ -0,0 +1,237 @@ +package excelize + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" +) + +func (f *File) processSpbType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return err + } + + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return err + } + spbIndex, err := strconv.Atoi(cellRichDataValue) + if err != nil { + return err + } + + if spbIndex < 0 || spbIndex >= len(richDataSpbs.SpbData.Spb) { + return fmt.Errorf("index out of range: %d", spbIndex) + } + + if cellRichStructure.N == "_Provider" { + // if provider is not in spb then needs handling + entityMap["_Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] + } else if cellRichStructure.N == "_Display" { + displayData := richDataSpbs.SpbData.Spb[spbIndex] + for spbDataValueIndex, spbDataValue := range displayData.V { + entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = spbDataValue + } + } + return nil +} + +func (f *File) processRichDataArrayType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, subRichStructure xlsxRichValueStructure, richValue *xlsxRichValueData) error { + richDataArray, err := f.richDataArrayReader() + if err != nil { + return err + } + + for subRichStructureIdx := range subRichStructure.K { + colCount := richDataArray.A[subRichStructureIdx].C + rows := make([][]interface{}, 0) + row := make([]interface{}, 0, colCount) + for richDataArrayValueIdx, richDataArrayValue := range richDataArray.A[subRichStructureIdx].V { + if richDataArrayValue.T == "s" { + row = append(row, richDataArrayValue.Text) + } else if richDataArrayValue.T == "r" { + arrayValueRichValueIdx, err := strconv.Atoi(richDataArrayValue.Text) + if err != nil { + return err + } + if arrayValueRichValueIdx < 0 || arrayValueRichValueIdx >= len(richValue.Rv) { + return fmt.Errorf("index out of range: %d", arrayValueRichValueIdx) + } + arrayValueRichValue := richValue.Rv[arrayValueRichValueIdx] + if arrayValueRichValue.Fb != "" { + unformattedValue := arrayValueRichValue.Fb + row = append(row, unformattedValue) + } + } + if (richDataArrayValueIdx+1)%colCount == 0 { + rows = append(rows, row) + row = make([]interface{}, 0, colCount) + } + } + if len(row) > 0 { + rows = append(rows, row) + } + entityMap[cellRichStructure.N] = rows + } + return nil +} + +func (f *File) processRichType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { + + cellRichDataValueInt, err := strconv.Atoi(cellRichDataValue) + if err != nil { + return err + } + + if cellRichDataValueInt < 0 || cellRichDataValueInt >= len(richValue.Rv) { + return fmt.Errorf("index out of range: %d", cellRichDataValueInt) + } + + subRichData := richValue.Rv[cellRichDataValueInt] + if subRichData.Fb != "" { + entityMap[cellRichStructure.N] = subRichData.Fb + } else { + richValueStructure, err := f.richStructureReader() + if err != nil { + return err + } + subRichStructure := richValueStructure.S[subRichData.S] + if subRichStructure.T == "_entity" { + // works only if all the nested entity values are unformatted strings + subRichEntityMap := make(map[string]interface{}) + for subRichDataValueIdx, subRichDatavalue := range subRichData.V { + subRichDataStructure := subRichStructure.K[subRichDataValueIdx].N + subRichEntityMap[subRichDataStructure] = subRichDatavalue + } + entityMap[cellRichStructure.N] = subRichEntityMap + } else if subRichStructure.T == "_array" { + err := f.processRichDataArrayType(entityMap, cellRichStructure, subRichStructure, richValue) + if err != nil { + return err + } + } + } + return nil +} +func (f *File) ReadEntity(sheet, cell string) ([]byte, error) { + + cellType, err := f.GetCellType(sheet, cell) + if err != nil { + return nil, err + } + if cellType != 3 { + return nil, errors.New("Cell is not of type entity") + } + + metadata, err := f.metadataReader() + if err != nil { + return nil, err + } + + ws, _ := f.workSheetReader(sheet) + ws.mu.Lock() + defer ws.mu.Unlock() + for _, row := range ws.SheetData.Row { + for _, c := range row.C { + if c.R == cell { + entity, err := f.readCellEntity(c, metadata) + if err != nil { + return nil, err + } + entityJSON, err := json.Marshal(entity) + if err != nil { + return nil, err + } + return entityJSON, nil + + } + } + } + return nil, nil +} + +func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata) (Entity, error) { + entity := Entity{} + entity.Type = "entity" + + entityMap := make(map[string]interface{}) + stringValueMap := make(map[string]string) + + cellMetadataIdx := *c.Vm - 1 + richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I + richValue, err := f.richValueReader() + if err != nil { + return entity, err + } + if richValueIdx >= len(richValue.Rv) { + return entity, err + } + + cellRichData := richValue.Rv[richValueIdx] + + richValueStructure, err := f.richStructureReader() + if err != nil { + return entity, err + } + + for cellRichDataIdx, cellRichDataValue := range cellRichData.V { + cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] + + if cellRichStructure.T == "" { + entityMap[cellRichStructure.N] = cellRichDataValue + } else if cellRichStructure.T == "b" { + boolValue := cellRichDataValue == "1" + entityMap[cellRichStructure.N] = boolValue + } else if cellRichStructure.T == "s" { + processStringType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue) + + } else if cellRichStructure.T == "r" { + err := f.processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) + if err != nil { + return entity, err + } + + } else if cellRichStructure.T == "spb" { + err := f.processSpbType(entityMap, cellRichStructure, cellRichDataValue) + if err != nil { + return entity, err + } + } + } + + entity.Text = entityMap["_DisplayString"].(string) + delete(entityMap, "_DisplayString") + + entity.Layouts.Compact.Icon = entityMap["_Icon"].(string) + delete(entityMap, "_Icon") + + if titleProp, ok := entityMap["TitleProperty"].(string); ok { + entity.Layouts.Card.Title.Property = titleProp + delete(entityMap, "TitleProperty") + } + if subTitleProp, ok := entityMap["SubTitleProperty"].(string); ok { + entity.Layouts.Card.SubTitle.Property = subTitleProp + delete(entityMap, "SubTitleProperty") + } + if providerDesc, ok := entityMap["_Provider"].(string); ok { + entity.Provider.Description = providerDesc + delete(entityMap, "_Provider") + } + entity.Properties = entityMap + + return entity, nil +} + +func processStringType(entityMap map[string]interface{}, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { + if cellRichStructure.N[0] == '_' { + if cellRichStructure.N == "_DisplayString" { + entityMap["_DisplayString"] = cellRichDataValue + } else if cellRichStructure.N == "_Icon" { + entityMap["_Icon"] = cellRichDataValue + } + } else { + entityMap[cellRichStructure.N] = cellRichDataValue + } +} diff --git a/entity_write.go b/entity_write.go new file mode 100644 index 0000000000..ec084ed6b1 --- /dev/null +++ b/entity_write.go @@ -0,0 +1,483 @@ +package excelize + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "os" + "sort" + "strconv" +) + +type Location struct { + array []int + subEntity []int +} + +var location Location + +func (f *File) AddEntity(sheet, cell string, entityData []byte) error { + err := f.checkOrCreateRichDataFiles() + if err != nil { + return err + } + err = f.writeMetadata() + if err != nil { + return err + } + err = f.writeSheetData(sheet, cell) + if err != nil { + return err + } + writeJSONToFile(string(entityData), "./console/mashalEntity.json") + + var entity Entity + err = json.Unmarshal(entityData, &entity) + if err != nil { + return err + } + if err := writeJSONToFile(entity, "./console/unmashalEntity.json"); err != nil { + //fmt.println("Error writing JSON to file:", err) + // return + } + + err = f.writeRdRichValueStructure(entity) + if err != nil { + return err + } + err = f.writeRdRichValue(entity) + if err != nil { + return err + } + err = f.writeSpbData(entity) + if err != nil { + return err + } + err = f.writeSpbStructure(entity) + if err != nil { + return err + } + + // f.WriteProvider(entity) + return nil +} + +func (f *File) writeRdRichValueStructure(entity Entity) error { + + richValueStructure, err := f.richStructureReader() + if err != nil { + return err + } + newRichValueStructureKeys := []xlsxRichValueStructureKey{} + if entity.Text != "" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: "_DisplayString", T: "s"}) + } + if entity.Layouts.Compact.Icon != "" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: "_Icon", T: "s"}) + } + if entity.Provider.Description != "" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: "_Provider", T: "spb"}) + } + properties := entity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) + } + sort.Strings(keys) + + var array_count int = 0 + for _, key := range keys { + propertyMap := properties[key].(map[string]interface{}) + if propertyMap["type"] == "String" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "s"}) // type needs to be determined and can vary from spb to r to s + } else if propertyMap["type"] == "Double" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key}) + } else if propertyMap["type"] == "Boolean" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "b"}) + } else if propertyMap["type"] == "Array" { + //append in _entity + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "r"}) + + arrayStructure, err := f.createArrayStructure(propertyMap["elements"]) + if err != nil { + return err + } + location.array = append(location.array, array_count) + array_count++ + richValueStructure.S = append(richValueStructure.S, arrayStructure) + + //creating new rv for array + + } + } + // fmt.Println(newRichValueStructureKeys) + + newRichValueStructure := xlsxRichValueStructure{ + T: "_entity", + K: newRichValueStructureKeys, + } + + richValueStructure.S = append(richValueStructure.S, newRichValueStructure) + richValueStructure.Count = strconv.Itoa(len(richValueStructure.S)) + // fmt.Println(richValueStructure) + xmlData, err := xml.Marshal(richValueStructure) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata"`)) + f.saveFileList(defaultXMLRichDataRichValueStructure, xmlData) + return nil + +} + +func (f *File) createArrayStructure(elements interface{}) (xlsxRichValueStructure, error) { + + newArrayRichValueStructure := []xlsxRichValueStructureKey{} + newArrayRichValueStructure = append(newArrayRichValueStructure, xlsxRichValueStructureKey{N: "array", T: "a"}) + + arrayRichStructure := xlsxRichValueStructure{ + T: "_array", + K: newArrayRichValueStructure, + } + return arrayRichStructure, nil +} + +func (f *File) writeRDRichArrayValue(data interface{}) (xlsxRichValue, error) { + newRichValue := xlsxRichValue{} + return newRichValue, nil +} + +func (f *File) writeRdRichValue(entity Entity) error { + richValueStructure, err := f.richStructureReader() + // _ = richDataArray + if err != nil { + return err + } + + richDataArray, err := f.richDataArrayReader() + // richDataArray.Count = 0 + // richDataArray.Xmlns s= "http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" + + if err != nil { + return err + } + structureValue := len(richValueStructure.S) - 1 + richValue, err := f.richValueReader() + if err != nil { + return err + } + richDataRichValues := []string{} + richDataRichValues = append(richDataRichValues, entity.Text) + richDataRichValues = append(richDataRichValues, entity.Layouts.Compact.Icon) + + if entity.Provider.Description != "" { + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return err + } + spbLen := len(richDataSpbs.SpbData.Spb) + richDataRichValues = append(richDataRichValues, strconv.Itoa(spbLen)) + } + + writeJSONToFile(entity.Properties, "./console/entityproperties.json") + var index int = 0 + var count int = 0 + var array_count int = 0 + + properties := entity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) + } + sort.Strings(keys) + + for _, key := range keys { + propertyMap := properties[key].(map[string]interface{}) + writeJSONToFile(properties[key], fmt.Sprintf("./console/propertyValue%d.json", index)) + index++ + if propertyMap["type"] == "String" { + richDataRichValues = append(richDataRichValues, propertyMap["basicValue"].(string)) + } else if propertyMap["type"] == "Double" { + richDataRichValues = append(richDataRichValues, fmt.Sprintf("%v", propertyMap["basicValue"])) + } else if propertyMap["type"] == "Boolean" { + if propertyMap["basicValue"] == true { + richDataRichValues = append(richDataRichValues, "1") + } else { + richDataRichValues = append(richDataRichValues, "0") + } + } else if propertyMap["type"] == "Array" { + richDataRichValues = append(richDataRichValues, strconv.Itoa(location.array[count])) + + //creating new rv for array + richDataRichArrayValues := []string{} + richDataRichArrayValues = append(richDataRichArrayValues, strconv.Itoa(count)) + newRichArrayValue := xlsxRichValue{ + S: array_count, + V: richDataRichArrayValues, + } + + richValue.Rv = append(richValue.Rv, newRichArrayValue) + + //creating rdarrayfile + + f.checkOrCreateXML(defaultXMLRichDataArray, []byte(xml.Header+templateRDArray)) + + writeJSONToFile(propertyMap["elements"], "./console/elements.json") + elements, ok := propertyMap["elements"].([]interface{}) + if !ok { + fmt.Println("Error: elements is not a slice") + return err + } + + maps := elements[0].([]interface{}) + cols := len(maps) + rows := len(elements) + + values_array := []xlsxRichArrayValue{} + + for _, element_row := range elements { + newRow, ok := element_row.([]interface{}) + if !ok { + fmt.Println("Error: elements is not a interface") + return err + } + for _, key := range newRow { + newMap := key.(map[string]interface{}) + + fmt.Println("\n\n\n\newMap") + fmt.Println(newMap) + xlsxRichArrayValue := xlsxRichArrayValue{ + Text: "basicValue", + T: "s", + } + values_array = append(values_array, xlsxRichArrayValue) + + } + } + + array_data := xlsxRichValuesArray{ + R: strconv.Itoa(rows), + C: cols, + V: values_array, + } + richDataArray.A = append(richDataArray.A, array_data) + richDataArray.Count++ + array_count++ + count++ + //for array + arrayData, err := xml.Marshal(richDataArray) + if err != nil { + return err + } + f.saveFileList(defaultXMLRichDataArray, arrayData) + + } + } + + newRichValue := xlsxRichValue{ + S: structureValue, + V: richDataRichValues, + } + richValue.Rv = append(richValue.Rv, newRichValue) + richValue.Count = len(richValue.Rv) + // fmt.Println(richValue) + xmlData, err := xml.Marshal(richValue) + if err != nil { + return err + } + f.saveFileList(defaultXMLRdRichValuePart, xmlData) + return nil +} + +func (f *File) writeMetadata() error { + richValue, err := f.richValueReader() + if err != nil { + return err + } + rvbIdx := len(richValue.Rv) + metadata, err := f.metadataReader() + if err != nil { + return err + } + richMetadataExists := checkRichMetadataExists(*metadata) + if !richMetadataExists { + newMetadataType := xlsxMetadataType{ + MetadataName: "XLRICHVALUE", + MinSupportedVersion: 120000, + Copy: 1, + PasteAll: 1, + PasteValues: 1, + Merge: 1, + SplitFirst: 1, + RowColShift: 1, + ClearFormats: 1, + ClearComments: 1, + Assign: 1, + Coerce: 1, + } + metadata.MetadataTypes.MetadataType = append(metadata.MetadataTypes.MetadataType, newMetadataType) + metadata.MetadataTypes.Count++ + } + var maxValuemetadataValue int + if metadata.ValueMetadata != nil { + maxValuemetadataValue = metadata.ValueMetadata.Bk[len(metadata.ValueMetadata.Bk)-1].Rc[0].V + } else { + maxValuemetadataValue = 0 + metadata.ValueMetadata = &xlsxMetadataBlocks{} + } + vmBlock := xlsxMetadataBlock{Rc: []xlsxMetadataRecord{ + { + T: 1, + V: maxValuemetadataValue, + }, + }} + metadata.ValueMetadata.Bk = append(metadata.ValueMetadata.Bk, vmBlock) + metadata.ValueMetadata.Count = len(metadata.ValueMetadata.Bk) + + fmBlock := xlsxFutureMetadataBlock{ + ExtLst: ExtLst{ + Ext: Ext{ + URI: ExtURIFutureMetadata, + Rvb: Rvb{ + I: rvbIdx, + }, + }, + }, + } + if len(metadata.FutureMetadata) == 0 { + metadata.FutureMetadata = append(metadata.FutureMetadata, xlsxFutureMetadata{}) + } + metadata.FutureMetadata[0].Bk = append(metadata.FutureMetadata[0].Bk, fmBlock) + metadata.FutureMetadata[0].Count = len(metadata.FutureMetadata[0].Bk) + metadata.FutureMetadata[0].Name = "XLRICHVALUE" + metadata.XmlnsXlrd = "http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" + metadata.Xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" + // fmt.Println(metadata) + xmlData, err := xml.Marshal(metadata) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`>`), []byte(`/>`)) + f.saveFileList(defaultXMLMetadata, xmlData) + return nil +} + +func checkRichMetadataExists(metadata xlsxMetadata) bool { + count := metadata.MetadataTypes.Count + if count > 0 { + for _, metadataType := range metadata.MetadataTypes.MetadataType { + if metadataType.MetadataName == "XLRICHVALUE" { + return true + } + } + } + return false +} + +func (f *File) writeSheetData(sheet, cell string) error { + ws, err := f.workSheetReader(sheet) + if err != nil { + return err + } + ws.mu.Lock() + defer ws.mu.Unlock() + c, col, row, err := ws.prepareCell(cell) + if err != nil { + return err + } + c.S = ws.prepareCellStyle(col, row, c.S) + metadata, err := f.metadataReader() + if err != nil { + return err + } + futureMetadataLen := len(metadata.FutureMetadata) + var vmValue int + if futureMetadataLen != 0 { + vmValue = len(metadata.FutureMetadata[0].Bk) + } else { + vmValue = 1 + } + vmValueUint := uint(vmValue) + c.Vm = &vmValueUint + c.V = "#VALUE!" + c.T = "e" + // fmt.Println(ws.SheetData) + return nil +} + +func (f *File) writeSpbData(entity Entity) error { + if entity.Provider.Description != "" { + f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBag, []byte(xml.Header+templateSpbData)) + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return err + } + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return err + } + + providerSpb := xlsxRichDataSpb{ + S: len(richDataSpbStructure.S), + V: []string{entity.Provider.Description}, + } + + richDataSpbs.SpbData.Spb = append(richDataSpbs.SpbData.Spb, providerSpb) + richDataSpbs.SpbData.Count++ + xmlData, err := xml.Marshal(richDataSpbs) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) + f.saveFileList(defaultXMLRichDataSupportingPropertyBag, xmlData) + } + return nil +} + +func (f *File) writeSpbStructure(entity Entity) error { + + if entity.Provider.Description != "" { + f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBagStructure, []byte(xml.Header+templateSpbStructure)) + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return err + } + + providerSpbStructureKey := xlsxRichDataSpbStructureKey{ + N: "name", + T: "s", + } + + providerSpbStructure := xlsxRichDataSpbStructure{} + providerSpbStructure.K = append(providerSpbStructure.K, providerSpbStructureKey) + + richDataSpbStructure.S = append(richDataSpbStructure.S, providerSpbStructure) + richDataSpbStructure.Count++ + xmlData, err := xml.Marshal(richDataSpbStructure) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) + f.saveFileList(defaultXMLRichDataSupportingPropertyBagStructure, xmlData) + + } + return nil +} + +func writeJSONToFile(data interface{}, filename string) error { + // Open a file for writing (create if not exists, truncate if exists) + file, err := os.Create(filename) + if err != nil { + return err + } + defer file.Close() + + // Encode the data to JSON and write it to the file + encoder := json.NewEncoder(file) + if err := encoder.Encode(data); err != nil { + return err + } + + return nil +} diff --git a/excelize.go b/excelize.go index f7dbbeff12..98dbd7e932 100644 --- a/excelize.go +++ b/excelize.go @@ -1,3 +1,7 @@ +// follow the standard of use or not use standalone=yes +// next step complete richdatavalue writer +// and then rdrichstructure writer + // Copyright 2016 - 2024 The excelize Authors. All rights reserved. Use of // this source code is governed by a BSD-style license that can be found in // the LICENSE file. @@ -15,9 +19,7 @@ package excelize import ( "archive/zip" "bytes" - "encoding/json" "encoding/xml" - "errors" "fmt" "io" "os" @@ -63,21 +65,33 @@ type File struct { } type Entity struct { - Type string `json:"type"` - Text string `json:"text"` - Layouts struct { - Compact struct { - Icon string `json:"icon"` - } `json:"compact"` - Card struct { - Title struct { - Property string `json:"property"` - } `json:"title"` - SubTitle struct { - Property string `json:"property"` - } `json:"subTitle"` - } `json:"card"` - } `json:"layouts"` + Type string `json:"type"` + Text string `json:"text"` + Layouts Layouts `json:"layouts,omitempty"` + Properties map[string]interface{} `json:"properties,omitempty"` + Provider Provider `json:"provider,omitempty"` +} + +type Layouts struct { + Compact Compact `json:"compact,omitempty"` + Card Card `json:"card,omitempty"` +} + +type Compact struct { + Icon string `json:"icon,omitempty"` +} + +type Card struct { + Title CardProperty `json:"title,omitempty"` + SubTitle CardProperty `json:"subTitle,omitempty"` +} + +type CardProperty struct { + Property string `json:"property,omitempty"` +} + +type Provider struct { + Description string `json:"description,omitempty"` } // charsetTranscoderFn set user-defined codepage transcoder function for open @@ -669,82 +683,6 @@ func (f *File) richDataArrayReader() (*xlsxRichValueArrayData, error) { return &richDataArray, nil } -func (f *File) TestRichValueReader() (*xlsxRichValueData, error) { - var richValue xlsxRichValueData - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRdRichValuePart)))). - Decode(&richValue); err != nil && err != io.EOF { - return &richValue, err - } - return &richValue, nil -} - -func (f *File) TestRichValueArrayDataReader() (*xlsxRichValueArrayData, error) { - var richValueArray xlsxRichValueArrayData - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataArray)))). - Decode(&richValueArray); err != nil && err != io.EOF { - return &richValueArray, err - } - return &richValueArray, nil -} - -func (f *File) TestRichValueStructureReader() (*xlsxRichValueStructures, error) { - var richValueStructures xlsxRichValueStructures - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueStructure)))). - Decode(&richValueStructures); err != nil && err != io.EOF { - return &richValueStructures, err - } - return &richValueStructures, nil -} - -func (f *File) TestRichDataSpb() (*XlsxRichDataSupportingPropertyBags, error) { - var richDataSpb XlsxRichDataSupportingPropertyBags - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBag)))). - Decode(&richDataSpb); err != nil && err != io.EOF { - return &richDataSpb, err - } - return &richDataSpb, nil -} - -func (f *File) TestRichDataSpbStructure() (*xlsxRichDataSpbStructures, error) { - var richDataSpbStructure xlsxRichDataSpbStructures - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataSupportingPropertyBagStructure)))). - Decode(&richDataSpbStructure); err != nil && err != io.EOF { - return &richDataSpbStructure, err - } - return &richDataSpbStructure, nil -} - -func (f *File) TestRichDataStyles() (*RichStyleSheet, error) { - var richDataStyle RichStyleSheet - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichStyles)))). - Decode(&richDataStyle); err != nil && err != io.EOF { - return &richDataStyle, err - } - return &richDataStyle, nil -} - -func (f *File) TestRichValueTypes() (*RvTypesInfo, error) { - var richDataTypes RvTypesInfo - if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichValueTypes)))). - Decode(&richDataTypes); err != nil && err != io.EOF { - return &richDataTypes, err - } - return &richDataTypes, nil -} - -// func (f *File) TestArrayData(sheet string) error { -// if err := checkSheetName(sheet); err != nil { -// return err -// } -// name := defaultXMLRichDataArray -// if xmlFile, ok := f.Sheet.Load(name); ok && xmlFile != nil { -// var arrayData xlsxRichValueArrayData -// output, _ := xml.Marshal(arrayData) -// f.saveFileList(name, f.replaceNameSpaceBytes(name, output)) -// } -// return nil -// } - func (f *File) checkOrCreateRichDataFiles() error { dirPath := filepath.Join(f.Path, "xl", "richData") if err := os.MkdirAll(dirPath, os.ModePerm); err != nil { @@ -752,7 +690,7 @@ func (f *File) checkOrCreateRichDataFiles() error { } f.checkOrCreateXML(defaultXMLRdRichValuePart, []byte(xml.Header+templateRichValue)) f.checkOrCreateXML(defaultXMLRichDataRichValueStructure, []byte(xml.Header+templateRichStructure)) - f.checkOrCreateXML(defaultXMLRichDataRichValueTypes, []byte(xml.Header+templateRichValuetypes)) + f.checkOrCreateXML(defaultXMLRichDataRichValueTypes, []byte(templateRichValuetypes)) return nil } @@ -762,244 +700,17 @@ func (f *File) checkOrCreateXML(name string, defaultContent []byte) { } } -func (f *File) AddEntity(sheet, cell string, entityData []byte) error { - f.checkOrCreateRichDataFiles() - ws, err := f.workSheetReader(sheet) - if err != nil { - return err - } - ws.mu.Lock() - defer ws.mu.Unlock() - for _, row := range ws.SheetData.Row { - for _, c := range row.C { - if c.R == cell { - err := f.writeCellEntity(cell, entityData) - return err - } - } - } - return nil -} - -func (f *File) writeCellEntity(cell string, entity []byte) error { - return nil -} - -func (f *File) ReadEntity(sheet, cell string) ([]byte, error) { - - cellType, err := f.GetCellType(sheet, cell) - if err != nil { - return nil, err - } - if cellType != 3 { - return nil, errors.New("Cell is not of type entity") - } - - metadata, err := f.metadataReader() - if err != nil { - return nil, err - } - - ws, _ := f.workSheetReader(sheet) - ws.mu.Lock() - defer ws.mu.Unlock() - entityStruct := Entity{} - for _, row := range ws.SheetData.Row { - for _, c := range row.C { - if c.R == cell { - err = f.readCellEntity(c, metadata, &entityStruct) - if err != nil { - return nil, err - } - entityJSON, err := json.Marshal(entityStruct) - if err != nil { - return nil, err - } - return entityJSON, nil - - } - } - } - return nil, nil -} - -func (f *File) readCellEntity(c xlsxC, metadata *xlsxMetadata, entity *Entity) error { - - entityMap := make(map[string]interface{}) - stringValueMap := make(map[string]string) - - cellMetadataIdx := *c.Vm - 1 - richValueIdx := metadata.FutureMetadata[0].Bk[cellMetadataIdx].ExtLst.Ext.Rvb.I - richValue, err := f.richValueReader() - if err != nil { - return err - } - if richValueIdx >= len(richValue.Rv) { - return err - } - - cellRichData := richValue.Rv[richValueIdx] - - richValueStructure, err := f.richStructureReader() - if err != nil { - return err - } - - for cellRichDataIdx, cellRichDataValue := range cellRichData.V { - cellRichStructure := richValueStructure.S[cellRichData.S].K[cellRichDataIdx] - - if cellRichStructure.T == "" { - entityMap[cellRichStructure.N] = cellRichDataValue - } else if cellRichStructure.T == "b" { - boolValue := cellRichDataValue == "1" - entityMap[cellRichStructure.N] = boolValue - } else if cellRichStructure.T == "s" { - processStringType(entityMap, stringValueMap, cellRichStructure, cellRichDataValue) - - } else if cellRichStructure.T == "r" { - err := f.processRichType(entityMap, cellRichStructure, cellRichDataValue, richValue) - if err != nil { - return err - } - - } else if cellRichStructure.T == "spb" { - err := f.processSpbType(entityMap, cellRichStructure, cellRichDataValue) - if err != nil { - return err - } - } - } - fmt.Println(stringValueMap) - fmt.Println(entityMap) - entity.Text = entityMap["_DisplayString"].(string) - entity.Layouts.Compact.Icon = entityMap["_Icon"].(string) - entity.Layouts.Card.Title.Property = entityMap["TitleProperty"].(string) - entity.Layouts.Card.SubTitle.Property = entityMap["SubTitleProperty"].(string) - - return nil -} - -func processStringType(entityMap map[string]interface{}, stringValueMap map[string]string, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) { - if cellRichStructure.N[0] == '_' { - if cellRichStructure.N == "_DisplayString" { - entityMap["_DisplayString"] = cellRichDataValue - } else if cellRichStructure.N == "_Icon" { - entityMap["_Icon"] = cellRichDataValue - } - } else { - stringValueMap[cellRichStructure.N] = cellRichDataValue - fmt.Println("Value is normal string") - fmt.Println("Key is:") - fmt.Println(cellRichStructure.N) - fmt.Println("Value is:") - fmt.Println(cellRichDataValue) - } -} - -func (f *File) processRichType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string, richValue *xlsxRichValueData) error { - - cellRichDataValueInt, err := strconv.Atoi(cellRichDataValue) - if err != nil { - return err - } - - if cellRichDataValueInt < 0 || cellRichDataValueInt >= len(richValue.Rv) { - return fmt.Errorf("index out of range: %d", cellRichDataValueInt) - } - - subRichData := richValue.Rv[cellRichDataValueInt] - if subRichData.Fb != "" { - entityMap[cellRichStructure.N] = subRichData.Fb - } else { - richValueStructure, err := f.richStructureReader() - if err != nil { - return err - } - subRichStructure := richValueStructure.S[subRichData.S] - if subRichStructure.T == "_entity" { - subRichEntityMap := make(map[string]interface{}) - for subRichDataValueIdx, subRichDatavalue := range subRichData.V { - subRichDataStructure := subRichStructure.K[subRichDataValueIdx].N - subRichEntityMap[subRichDataStructure] = subRichDatavalue - } - entityMap[cellRichStructure.N] = subRichEntityMap - } else if subRichStructure.T == "_array" { - err := f.processRichDataArrayType(entityMap, cellRichStructure, subRichStructure, richValue) - if err != nil { - return err - } - } - } - return nil -} -func (f *File) processRichDataArrayType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, subRichStructure xlsxRichValueStructure, richValue *xlsxRichValueData) error { - richDataArray, err := f.richDataArrayReader() - if err != nil { - return err - } - - for subRichStructureIdx := range subRichStructure.K { - colCount := richDataArray.A[subRichStructureIdx].C - rows := make([][]interface{}, 0) - row := make([]interface{}, 0, colCount) - for richDataArrayValueIdx, richDataArrayValue := range richDataArray.A[subRichStructureIdx].V { - if richDataArrayValue.T == "s" { - row = append(row, richDataArrayValue.Text) - } else if richDataArrayValue.T == "r" { - arrayValueRichValueIdx, err := strconv.Atoi(richDataArrayValue.Text) - if err != nil { - return err - } - if arrayValueRichValueIdx < 0 || arrayValueRichValueIdx >= len(richValue.Rv) { - return fmt.Errorf("index out of range: %d", arrayValueRichValueIdx) - } - arrayValueRichValue := richValue.Rv[arrayValueRichValueIdx] - if arrayValueRichValue.Fb != "" { - unformattedValue := arrayValueRichValue.Fb - row = append(row, unformattedValue) - } - } - if (richDataArrayValueIdx+1)%colCount == 0 { - rows = append(rows, row) - row = make([]interface{}, 0, colCount) - } - } - if len(row) > 0 { - rows = append(rows, row) - } - entityMap[cellRichStructure.N] = rows - } - return nil -} -func (f *File) processSpbType(entityMap map[string]interface{}, cellRichStructure xlsxRichValueStructureKey, cellRichDataValue string) error { - richDataSpbs, err := f.richDataSpbReader() - if err != nil { - return err - } - - richDataSpbStructure, err := f.richDataSpbStructureReader() - if err != nil { - return err - } - spbIndex, err := strconv.Atoi(cellRichDataValue) - if err != nil { - return err - } - - if spbIndex < 0 || spbIndex >= len(richDataSpbs.SpbData.Spb) { - return fmt.Errorf("index out of range: %d", spbIndex) - } - - if cellRichStructure.N == "_Provider" { - entityMap["_Provider"] = richDataSpbs.SpbData.Spb[spbIndex].V[0] - } else if cellRichStructure.N == "_Display" { - displayData := richDataSpbs.SpbData.Spb[spbIndex] - for spbDataValueIndex, spbDataValue := range displayData.V { - entityMap[richDataSpbStructure.S[displayData.S].K[spbDataValueIndex].N] = spbDataValue - } - } - return nil -} +// func (f *File) WriteProvider(entity Entity) error { +// f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBag, []byte(xml.Header+templateSpbData)) +// f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBagStructure, []byte(xml.Header+templateSpbData)) +// spbData, err := f.richDataSpbReader() +// if err != nil { +// return err +// } +// spbStructure, err := f.richDataSpbStructureReader() +// provider := entity.Provider.Description +// return nil +// } // richValueRelReader provides a function to get the pointer to the structure // after deserialization of xl/richData/richValueRel.xml. diff --git a/excelize_test.go b/excelize_test.go index c441b5e169..9e4a7fea7c 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -1699,3 +1699,147 @@ func BenchmarkOpenFile(b *testing.B) { } } } + +func TestEntityWriter(t *testing.T) { + jsonFile, err := os.Open("test/testEntity.json") + if err != nil { + assert.NoError(t, err) + } + defer jsonFile.Close() + + byteValue, _ := io.ReadAll(jsonFile) + + f := NewFile() + defer func() { + if err := f.Close(); err != nil { + assert.NoError(t, err) + } + }() + + index, err := f.NewSheet("Sheet1") + if err != nil { + assert.NoError(t, err) + return + } + f.SetActiveSheet(index) + + err = f.AddEntity("Sheet1", "A1", byteValue) + if err != nil { + assert.NoError(t, err) + } + + if err := f.SaveAs("test/TestEntity.xlsx"); err != nil { + assert.NoError(t, err) + } + +} + +func TestEntityAndCellWriter(t *testing.T) { + jsonFile, err := os.Open("test/testEntity.json") + if err != nil { + assert.NoError(t, err) + } + defer jsonFile.Close() + + byteValue, _ := io.ReadAll(jsonFile) + + f := NewFile() + defer func() { + if err := f.Close(); err != nil { + assert.NoError(t, err) + } + }() + + index, err := f.NewSheet("Sheet1") + if err != nil { + assert.NoError(t, err) + return + } + f.SetActiveSheet(index) + + err = f.AddEntity("Sheet1", "A1", byteValue) + if err != nil { + assert.NoError(t, err) + } + f.SetCellValue("Sheet1", "A2", "Hello world.") + + if err := f.SaveAs("test/TestEntity.xlsx"); err != nil { + assert.NoError(t, err) + } + +} + +func TestMultipleEntityWriter(t *testing.T) { + jsonFile, err := os.Open("test/testEntity.json") + if err != nil { + assert.NoError(t, err) + } + defer jsonFile.Close() + + byteValue, _ := io.ReadAll(jsonFile) + + f := NewFile() + defer func() { + if err := f.Close(); err != nil { + assert.NoError(t, err) + } + }() + + index, err := f.NewSheet("Sheet1") + if err != nil { + assert.NoError(t, err) + return + } + f.SetActiveSheet(index) + + err = f.AddEntity("Sheet1", "A1", byteValue) + if err != nil { + assert.NoError(t, err) + } + err = f.AddEntity("Sheet1", "A2", byteValue) + if err != nil { + assert.NoError(t, err) + } + if err := f.SaveAs("test/TestEntity.xlsx"); err != nil { + assert.NoError(t, err) + } + +} + +func TestOverwriteEntityWriter(t *testing.T) { + jsonFile, err := os.Open("test/testEntity.json") + if err != nil { + assert.NoError(t, err) + } + defer jsonFile.Close() + + byteValue, _ := io.ReadAll(jsonFile) + + f := NewFile() + defer func() { + if err := f.Close(); err != nil { + assert.NoError(t, err) + } + }() + + index, err := f.NewSheet("Sheet1") + if err != nil { + assert.NoError(t, err) + return + } + f.SetActiveSheet(index) + + err = f.AddEntity("Sheet1", "A1", byteValue) + if err != nil { + assert.NoError(t, err) + } + err = f.AddEntity("Sheet1", "A1", byteValue) + if err != nil { + assert.NoError(t, err) + } + + if err := f.SaveAs("test/TestEntity.xlsx"); err != nil { + assert.NoError(t, err) + } + +} diff --git a/rich_data_test.go b/rich_data_test.go deleted file mode 100644 index 0f14bcb6bb..0000000000 --- a/rich_data_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package excelize - -import ( - "fmt" - "testing" -) - -func TestRichDataInsert(t *testing.T) { - f := NewFile() - f.Pkg.Store(defaultXMLMetadata, []byte(``)) - f.Pkg.Store(defaultXMLRdRichValuePart, []byte(`05`)) - f.Pkg.Store(defaultXMLRdRichValueRel, []byte(``)) - f.Pkg.Store(defaultXMLRdRichValueRelRels, []byte(fmt.Sprintf(``, SourceRelationshipImage))) - 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)}}}, - }}, - }) -} diff --git a/templates.go b/templates.go index 37310d9f84..abb2ee9e63 100644 --- a/templates.go +++ b/templates.go @@ -128,6 +128,7 @@ const ( ExtURIWebExtensions = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}" ExtURIWorkbookPrX14 = "{79F54976-1DA5-4618-B147-ACDE4B953A38}" ExtURIWorkbookPrX15 = "{140A7094-0E35-4892-8432-C4D2E57EDEB5}" + ExtURIFutureMetadata = "{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}" ) // workbookExtURIPriority is the priority of URI in the workbook extension lists. @@ -505,7 +506,7 @@ var builtInDefinedNames = []string{"_xlnm.Print_Area", "_xlnm.Print_Titles", "_x const templateDocpropsApp = `0Go Excelize` -const templateContentTypes = `` +const templateContentTypes = `` const templateWorkbook = `` @@ -513,7 +514,7 @@ const templateStyles = `` -const templateWorkbookRels = `` +const templateWorkbookRels = `` const templateDocpropsCore = `xuri2006-09-16T00:00:00Z2006-09-16T00:00:00Z` @@ -523,8 +524,15 @@ const templateTheme = `` -const templateRichValue = `` +const templateRichValue = `` -const templateRichStructure = `` +const templateRichStructure = `` -const templateRichValuetypes = `` +const templateRichValuetypes = `` + +const templateSpbData = `` + +const templateSpbStructure = `` + +const templateRDArray = ` +` diff --git a/test/testEntity.json b/test/testEntity.json new file mode 100644 index 0000000000..262d7348fb --- /dev/null +++ b/test/testEntity.json @@ -0,0 +1,35 @@ +{ + "type": "Entity", + "text": "Card Top Title", + "properties": { + "Effective Date": { + "type": "FormattedNumber", + "basicValue": 29253, + "numberFormat": "yyyy-mm-dd" + }, + "Owner": { "type": "String", "basicValue": "Jan Krynauw" }, + "Price": { + "type": "FormattedNumber", + "basicValue": 55.4, + "numberFormat": "$0.00" + }, + "Sub Properties A": { + "type": "Entity", + "text": "Another one", + "properties": { + "Key 1": { "type": "String", "basicValue": "Value 1" }, + "Key 2": { "type": "String", "basicValue": "Value 2" } + } + }, + "Total Amount": { "type": "Double", "basicValue": 7777.77 }, + "Validated": { "type": "Boolean", "basicValue": true } + }, + "layouts": { + "compact": { "icon": "Cloud" }, + "card": { + "title": { "property": "Owner" }, + "subTitle": { "property": "Effective Date" } + } + }, + "provider": { "description": "Some nice description" } +} diff --git a/xmlMetaData.go b/xmlMetaData.go index dc0ed1c8d4..cfc100e109 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -24,7 +24,9 @@ import "encoding/xml" // can be propagated along with the value as it is referenced in formulas. type xlsxMetadata struct { XMLName xml.Name `xml:"metadata"` - MetadataTypes *xlsxInnerXML `xml:"metadataTypes"` + Xmlns string `xml:"xmlns,attr"` + XmlnsXlrd string `xml:"xmlns:xlrd,attr"` + MetadataTypes xlsxMetadataTypes `xml:"metadataTypes"` MetadataStrings *xlsxInnerXML `xml:"metadataStrings"` MdxMetadata *xlsxInnerXML `xml:"mdxMetadata"` FutureMetadata []xlsxFutureMetadata `xml:"futureMetadata"` @@ -33,9 +35,31 @@ type xlsxMetadata struct { ExtLst *xlsxInnerXML `xml:"extLst"` } +type xlsxMetadataTypes struct { + Count int `xml:"count,attr"` + MetadataType []xlsxMetadataType `xml:"metadataType"` +} + +type xlsxMetadataType struct { + MetadataName string `xml:"name,attr"` + MinSupportedVersion int `xml:"minSupportedVersion,attr"` + Copy int `xml:"copy,attr"` + PasteAll int `xml:"pasteAll,attr"` + PasteValues int `xml:"pasteValues,attr"` + Merge int `xml:"merge,attr"` + SplitFirst int `xml:"splitFirst,attr"` + RowColShift int `xml:"rowColShift,attr"` + ClearFormats int `xml:"clearFormats,attr"` + ClearComments int `xml:"clearComments,attr"` + Assign int `xml:"assign,attr"` + Coerce int `xml:"coerce,attr"` +} + // xlsxFutureMetadata directly maps the futureMetadata element. This element // represents future metadata information. type xlsxFutureMetadata struct { + Name string `xml:"name,attr"` + Count int `xml:"count,attr"` Bk []xlsxFutureMetadataBlock `xml:"bk"` ExtLst *xlsxInnerXML `xml:"extLst"` } @@ -44,14 +68,20 @@ type xlsxFutureMetadata struct { // a block of future metadata information. This is a location for storing // feature extension information. type xlsxFutureMetadataBlock struct { - ExtLst struct { - Ext struct { - URI string `xml:"uri,attr"` - Rvb struct { - I int `xml:"i,attr"` - } `xml:"rvb"` - } `xml:"ext"` - } `xml:"extLst"` + ExtLst ExtLst `xml:"extLst"` +} + +type ExtLst struct { + Ext Ext `xml:"ext"` +} + +type Ext struct { + URI string `xml:"uri,attr"` + Rvb Rvb `xml:"xlrd:rvb"` +} + +type Rvb struct { + I int `xml:"i,attr"` } // xlsxMetadataBlocks directly maps the metadata element. This element @@ -78,10 +108,10 @@ type xlsxMetadataRecord struct { // xlsxRichValueArrayData directly maps the arrayData element that specifies rich value // arrays. type xlsxRichValueArrayData struct { - XMLName xml.Name `xml:"arrayData"` - Xmlns string `xml:"xmlns,attr"` - Count string `xml:"count,attr"` - A []xlsxRichValuesArray `xml:"a"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 arrayData"` + // Xmlns string `xml:"xmlns,attr"` + Count int `xml:"count,attr"` + A []xlsxRichValuesArray `xml:"a"` } // xlsxRichValuesArray directly maps the a element that specifies rich values Array @@ -102,7 +132,7 @@ type xlsxRichArrayValue struct { // xlsxRichValueData directly maps the rvData element that specifies rich value // data. type xlsxRichValueData struct { - XMLName xml.Name `xml:"rvData"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata rvData"` Count int `xml:"count,attr,omitempty"` Rv []xlsxRichValue `xml:"rv"` ExtLst *xlsxInnerXML `xml:"extLst"` @@ -133,7 +163,7 @@ type xlsxRichValueRelRelationship struct { // XlsxRichValueStructures directly maps the rvStructures element that specifies rich value structure // data. type xlsxRichValueStructures struct { - XMLName xml.Name `xml:"rvStructures"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata rvStructures"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` Count string `xml:"count,attr"` @@ -153,12 +183,12 @@ type xlsxRichValueStructure struct { type xlsxRichValueStructureKey struct { Text string `xml:",chardata"` N string `xml:"n,attr"` - T string `xml:"t,attr"` + T string `xml:"t,attr,omitempty"` } // XlsxRichDataSupportingPropertyBags directly maps the supportingPropertyBags element that specifies supporting property bag data. type XlsxRichDataSupportingPropertyBags struct { - XMLName xml.Name `xml:"supportingPropertyBags"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 supportingPropertyBags"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` SpbData xlsxRichDataSpbData `xml:"spbData"` @@ -167,23 +197,23 @@ type XlsxRichDataSupportingPropertyBags struct { // XlsxRichDataSpbData directly maps the spbData element that specifies supporting property bag data. type xlsxRichDataSpbData struct { Text string `xml:",chardata"` - Count string `xml:"count,attr"` + Count int `xml:"count,attr"` Spb []xlsxRichDataSpb `xml:"spb"` } // XlsxRichDataSpb directly maps the spb element that specifies data for a single supporting property bag. type xlsxRichDataSpb struct { - Text string `xml:",chardata"` - S int `xml:"s,attr"` - V []string `xml:"v"` + // Text string `xml:",chardata"` + S int `xml:"s,attr"` + V []string `xml:"v"` } // XlsxRichDataSpbStructures directly maps the spbStructures element that specifies supporting property bag structure. type xlsxRichDataSpbStructures struct { - XMLName xml.Name `xml:"spbStructures"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 spbStructures"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` - Count string `xml:"count,attr"` + Count int `xml:"count,attr"` S []xlsxRichDataSpbStructure `xml:"s"` } @@ -201,7 +231,7 @@ type xlsxRichDataSpbStructureKey struct { } type RvTypesInfo struct { - XMLName xml.Name `xml:"rvTypesInfo"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 rvTypesInfo"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` Mc string `xml:"mc,attr"` @@ -231,7 +261,7 @@ type Flag struct { // this is where the richdatatyle file starts type RichStyleSheet struct { - XMLName xml.Name `xml:"richStyleSheet"` + XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 richStyleSheet"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` Mc string `xml:"mc,attr"` From d443d6cbfcac049657ffd9b23c18905c7e6eb97d Mon Sep 17 00:00:00 2001 From: hamzaanis Date: Wed, 22 May 2024 15:35:16 +0500 Subject: [PATCH 28/28] subentity, formatted and array data functional --- entity_read.go | 4 +- entity_write.go | 469 ++++++++++++++++++++++++++++++++----------- excelize.go | 9 + excelize_test.go | 75 ------- templates.go | 1 + test/testEntity.json | 46 ++++- xmlMetaData.go | 4 +- 7 files changed, 409 insertions(+), 199 deletions(-) diff --git a/entity_read.go b/entity_read.go index 4877f9118f..355504640f 100644 --- a/entity_read.go +++ b/entity_read.go @@ -60,7 +60,7 @@ func (f *File) processRichDataArrayType(entityMap map[string]interface{}, cellRi return fmt.Errorf("index out of range: %d", arrayValueRichValueIdx) } arrayValueRichValue := richValue.Rv[arrayValueRichValueIdx] - if arrayValueRichValue.Fb != "" { + if arrayValueRichValue.Fb != 0 { unformattedValue := arrayValueRichValue.Fb row = append(row, unformattedValue) } @@ -90,7 +90,7 @@ func (f *File) processRichType(entityMap map[string]interface{}, cellRichStructu } subRichData := richValue.Rv[cellRichDataValueInt] - if subRichData.Fb != "" { + if subRichData.Fb != 0 { entityMap[cellRichStructure.N] = subRichData.Fb } else { richValueStructure, err := f.richStructureReader() diff --git a/entity_write.go b/entity_write.go index ec084ed6b1..bdb2b492d1 100644 --- a/entity_write.go +++ b/entity_write.go @@ -5,42 +5,43 @@ import ( "encoding/json" "encoding/xml" "fmt" - "os" "sort" "strconv" + "strings" + "time" ) type Location struct { - array []int - subEntity []int + maxRdRichValueStructureIndex int + maxRdRichValueIndex int + spbStructureIndex int + arrayCount int + spbDataIndex int } -var location Location +var location = Location{ + maxRdRichValueStructureIndex: 0, + maxRdRichValueIndex: 0, + spbStructureIndex: 0, + arrayCount: 0, + spbDataIndex: 0, +} func (f *File) AddEntity(sheet, cell string, entityData []byte) error { err := f.checkOrCreateRichDataFiles() if err != nil { return err } - err = f.writeMetadata() - if err != nil { - return err - } err = f.writeSheetData(sheet, cell) if err != nil { return err } - writeJSONToFile(string(entityData), "./console/mashalEntity.json") var entity Entity err = json.Unmarshal(entityData, &entity) if err != nil { return err } - if err := writeJSONToFile(entity, "./console/unmashalEntity.json"); err != nil { - //fmt.println("Error writing JSON to file:", err) - // return - } err = f.writeRdRichValueStructure(entity) if err != nil { @@ -50,6 +51,10 @@ func (f *File) AddEntity(sheet, cell string, entityData []byte) error { if err != nil { return err } + err = f.writeMetadata() + if err != nil { + return err + } err = f.writeSpbData(entity) if err != nil { return err @@ -58,9 +63,12 @@ func (f *File) AddEntity(sheet, cell string, entityData []byte) error { if err != nil { return err } - - // f.WriteProvider(entity) + // err = f.writeRichStyles(entity) + // if err != nil { + // return err + // } return nil + } func (f *File) writeRdRichValueStructure(entity Entity) error { @@ -70,6 +78,9 @@ func (f *File) writeRdRichValueStructure(entity Entity) error { return err } newRichValueStructureKeys := []xlsxRichValueStructureKey{} + if entity.Layouts.Card.Title.Property != "" || entity.Layouts.Card.SubTitle.Property != "" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: "_Display", T: "spb"}) + } if entity.Text != "" { newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: "_DisplayString", T: "s"}) } @@ -86,32 +97,47 @@ func (f *File) writeRdRichValueStructure(entity Entity) error { } sort.Strings(keys) - var array_count int = 0 for _, key := range keys { propertyMap := properties[key].(map[string]interface{}) if propertyMap["type"] == "String" { - newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "s"}) // type needs to be determined and can vary from spb to r to s + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "s"}) } else if propertyMap["type"] == "Double" { newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key}) + } else if propertyMap["type"] == "FormattedNumber" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "s"}) } else if propertyMap["type"] == "Boolean" { newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "b"}) } else if propertyMap["type"] == "Array" { //append in _entity newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "r"}) - arrayStructure, err := f.createArrayStructure(propertyMap["elements"]) + arrayStructure, err := f.createArrayStructure() if err != nil { return err } - location.array = append(location.array, array_count) - array_count++ richValueStructure.S = append(richValueStructure.S, arrayStructure) //creating new rv for array + } else if propertyMap["type"] == "Entity" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "r"}) + subEntityJson, err := json.Marshal(propertyMap) + if err != nil { + fmt.Println(err) + } + var subEntity Entity + err = json.Unmarshal(subEntityJson, &subEntity) + if err != nil { + fmt.Println(err) + } + + err = f.writeSubEntityRdRichValueStructure(subEntity, richValueStructure) + if err != nil { + return err + } + } } - // fmt.Println(newRichValueStructureKeys) newRichValueStructure := xlsxRichValueStructure{ T: "_entity", @@ -120,7 +146,6 @@ func (f *File) writeRdRichValueStructure(entity Entity) error { richValueStructure.S = append(richValueStructure.S, newRichValueStructure) richValueStructure.Count = strconv.Itoa(len(richValueStructure.S)) - // fmt.Println(richValueStructure) xmlData, err := xml.Marshal(richValueStructure) if err != nil { return err @@ -131,7 +156,66 @@ func (f *File) writeRdRichValueStructure(entity Entity) error { } -func (f *File) createArrayStructure(elements interface{}) (xlsxRichValueStructure, error) { +func (f *File) writeSubEntityRdRichValueStructure(subEntity Entity, richValueStructures *xlsxRichValueStructures) error { + properties := subEntity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) + } + sort.Strings(keys) + newRichValueStructureKeys := []xlsxRichValueStructureKey{} + + if subEntity.Text != "" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: "_DisplayString", T: "s"}) + } + + for _, key := range keys { + propertyMap := properties[key].(map[string]interface{}) + if propertyMap["type"] == "String" { + newRichValueStructureKeys = append(newRichValueStructureKeys, xlsxRichValueStructureKey{N: key, T: "s"}) + } + } + + richValueStructure := xlsxRichValueStructure{ + T: "_entity", + K: newRichValueStructureKeys, + } + richValueStructures.S = append(richValueStructures.S, richValueStructure) + + return nil +} + +func (f *File) writeSubentityRdRichValue(subEntity Entity, richValueData *xlsxRichValueData) error { + + properties := subEntity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) + } + sort.Strings(keys) + + richDataRichValues := []string{} + richDataRichValues = append(richDataRichValues, subEntity.Text) + for _, key := range keys { + propertyMap := properties[key].(map[string]interface{}) + if propertyMap["type"] == "String" { + richDataRichValues = append(richDataRichValues, propertyMap["basicValue"].(string)) + } + } + + newRichValue := xlsxRichValue{ + S: location.maxRdRichValueStructureIndex, + V: richDataRichValues, + } + location.maxRdRichValueStructureIndex++ + + richValueData.Rv = append(richValueData.Rv, newRichValue) + location.maxRdRichValueIndex++ + + return nil +} + +func (f *File) createArrayStructure() (xlsxRichValueStructure, error) { newArrayRichValueStructure := []xlsxRichValueStructureKey{} newArrayRichValueStructure = append(newArrayRichValueStructure, xlsxRichValueStructureKey{N: "array", T: "a"}) @@ -143,47 +227,53 @@ func (f *File) createArrayStructure(elements interface{}) (xlsxRichValueStructur return arrayRichStructure, nil } -func (f *File) writeRDRichArrayValue(data interface{}) (xlsxRichValue, error) { - newRichValue := xlsxRichValue{} - return newRichValue, nil -} +func (f *File) createArrayFbStructure(elements interface{}) (xlsxRichValueStructure, error) { + var arrayFbStructure xlsxRichValueStructure -func (f *File) writeRdRichValue(entity Entity) error { - richValueStructure, err := f.richStructureReader() - // _ = richDataArray - if err != nil { - return err - } + arrayElements := elements.([]interface{}) + for _, element_row := range arrayElements { + newRow := element_row.([]interface{}) + for _, key := range newRow { + newMap := key.(map[string]interface{}) - richDataArray, err := f.richDataArrayReader() - // richDataArray.Count = 0 - // richDataArray.Xmlns s= "http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" + if newMap["type"].(string) == "FormattedNumber" { - if err != nil { - return err + newArrayFbStructure := []xlsxRichValueStructureKey{} + newArrayFbStructure = append(newArrayFbStructure, xlsxRichValueStructureKey{N: "_Format", T: "spb"}) + + arrayFbStructure = xlsxRichValueStructure{ + T: "_formattednumber", + K: newArrayFbStructure, + } + + } + } } - structureValue := len(richValueStructure.S) - 1 + + return arrayFbStructure, nil +} + +func (f *File) writeRdRichValue(entity Entity) error { richValue, err := f.richValueReader() if err != nil { return err } richDataRichValues := []string{} + if entity.Layouts.Card.Title.Property != "" || entity.Layouts.Card.SubTitle.Property != "" { + richDataRichValues = append(richDataRichValues, strconv.Itoa(location.spbDataIndex)) + location.spbDataIndex++ + } richDataRichValues = append(richDataRichValues, entity.Text) - richDataRichValues = append(richDataRichValues, entity.Layouts.Compact.Icon) - + if entity.Layouts.Compact.Icon != "" { + richDataRichValues = append(richDataRichValues, entity.Layouts.Compact.Icon) + } if entity.Provider.Description != "" { - richDataSpbs, err := f.richDataSpbReader() - if err != nil { - return err - } - spbLen := len(richDataSpbs.SpbData.Spb) - richDataRichValues = append(richDataRichValues, strconv.Itoa(spbLen)) + + richDataRichValues = append(richDataRichValues, strconv.Itoa(location.spbDataIndex)) + location.spbDataIndex++ } - writeJSONToFile(entity.Properties, "./console/entityproperties.json") var index int = 0 - var count int = 0 - var array_count int = 0 properties := entity.Properties keys := make([]string, 0, len(properties)) @@ -194,10 +284,29 @@ func (f *File) writeRdRichValue(entity Entity) error { for _, key := range keys { propertyMap := properties[key].(map[string]interface{}) - writeJSONToFile(properties[key], fmt.Sprintf("./console/propertyValue%d.json", index)) index++ if propertyMap["type"] == "String" { richDataRichValues = append(richDataRichValues, propertyMap["basicValue"].(string)) + } else if propertyMap["type"] == "FormattedNumber" { + formattedValue := propertyMap["basicValue"].(float64) + var formattedString string + if propertyMap["numberFormat"] == "yyyy-mm-dd" { + base := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + formattedDateValue := int(formattedValue) + target := base.AddDate(0, 0, formattedDateValue-2) + formattedString = target.Format("2006-01-02") + } else { + numFormat := propertyMap["numberFormat"] + firstChar := string(numFormat.(string)[0]) + parts := strings.Split(numFormat.(string), ".") + decimalPlaces := 0 + if len(parts) > 1 { + decimalPlaces = strings.Count(parts[1], "0") + } + formattedString = fmt.Sprintf("%s%.*f", firstChar, decimalPlaces, formattedValue) + } + richDataRichValues = append(richDataRichValues, formattedString) + } else if propertyMap["type"] == "Double" { richDataRichValues = append(richDataRichValues, fmt.Sprintf("%v", propertyMap["basicValue"])) } else if propertyMap["type"] == "Boolean" { @@ -207,23 +316,25 @@ func (f *File) writeRdRichValue(entity Entity) error { richDataRichValues = append(richDataRichValues, "0") } } else if propertyMap["type"] == "Array" { - richDataRichValues = append(richDataRichValues, strconv.Itoa(location.array[count])) + richDataRichValues = append(richDataRichValues, strconv.Itoa(location.maxRdRichValueIndex)) //creating new rv for array richDataRichArrayValues := []string{} - richDataRichArrayValues = append(richDataRichArrayValues, strconv.Itoa(count)) + richDataRichArrayValues = append(richDataRichArrayValues, strconv.Itoa(location.arrayCount)) + location.arrayCount++ newRichArrayValue := xlsxRichValue{ - S: array_count, + S: location.maxRdRichValueStructureIndex, V: richDataRichArrayValues, } + location.maxRdRichValueStructureIndex++ richValue.Rv = append(richValue.Rv, newRichArrayValue) + location.maxRdRichValueIndex++ //creating rdarrayfile f.checkOrCreateXML(defaultXMLRichDataArray, []byte(xml.Header+templateRDArray)) - writeJSONToFile(propertyMap["elements"], "./console/elements.json") elements, ok := propertyMap["elements"].([]interface{}) if !ok { fmt.Println("Error: elements is not a slice") @@ -245,17 +356,49 @@ func (f *File) writeRdRichValue(entity Entity) error { for _, key := range newRow { newMap := key.(map[string]interface{}) - fmt.Println("\n\n\n\newMap") - fmt.Println(newMap) - xlsxRichArrayValue := xlsxRichArrayValue{ - Text: "basicValue", - T: "s", + if newMap["type"].(string) == "String" { + basicValue := newMap["basicValue"].(string) + + xlsxRichArrayValue := xlsxRichArrayValue{ + Text: basicValue, + T: "s", + } + values_array = append(values_array, xlsxRichArrayValue) + } else if newMap["type"].(string) == "FormattedNumber" { + + formattedValue := newMap["basicValue"].(float64) + var formattedString string + if newMap["numberFormat"] == "yyyy-mm-dd" { + base := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + formattedDateValue := int(formattedValue) + target := base.AddDate(0, 0, formattedDateValue-2) + formattedString = target.Format("2006-01-02") + } else { + numFormat := newMap["numberFormat"] + firstChar := string(numFormat.(string)[0]) + parts := strings.Split(numFormat.(string), ".") + decimalPlaces := 0 + if len(parts) > 1 { + decimalPlaces = strings.Count(parts[1], "0") + } + formattedString = fmt.Sprintf("%s%.*f", firstChar, decimalPlaces, formattedValue) + } + xlsxRichArrayValue := xlsxRichArrayValue{ + Text: formattedString, + T: "s", + } + values_array = append(values_array, xlsxRichArrayValue) + } - values_array = append(values_array, xlsxRichArrayValue) } } + richDataArray, err := f.richDataArrayReader() + if err != nil { + return err + } + array_data := xlsxRichValuesArray{ R: strconv.Itoa(rows), C: cols, @@ -263,25 +406,38 @@ func (f *File) writeRdRichValue(entity Entity) error { } richDataArray.A = append(richDataArray.A, array_data) richDataArray.Count++ - array_count++ - count++ - //for array + arrayData, err := xml.Marshal(richDataArray) if err != nil { return err } f.saveFileList(defaultXMLRichDataArray, arrayData) + } else if propertyMap["type"] == "Entity" { + richDataRichValues = append(richDataRichValues, strconv.Itoa(location.maxRdRichValueIndex)) + + subEntityJson, err := json.Marshal(propertyMap) + if err != nil { + fmt.Println(err) + } + var subEntity Entity + err = json.Unmarshal(subEntityJson, &subEntity) + if err != nil { + fmt.Println(err) + } + + f.writeSubentityRdRichValue(subEntity, richValue) } } newRichValue := xlsxRichValue{ - S: structureValue, + S: location.maxRdRichValueStructureIndex, V: richDataRichValues, } + location.maxRdRichValueStructureIndex++ + richValue.Rv = append(richValue.Rv, newRichValue) richValue.Count = len(richValue.Rv) - // fmt.Println(richValue) xmlData, err := xml.Marshal(richValue) if err != nil { return err @@ -291,11 +447,6 @@ func (f *File) writeRdRichValue(entity Entity) error { } func (f *File) writeMetadata() error { - richValue, err := f.richValueReader() - if err != nil { - return err - } - rvbIdx := len(richValue.Rv) metadata, err := f.metadataReader() if err != nil { return err @@ -340,7 +491,7 @@ func (f *File) writeMetadata() error { Ext: Ext{ URI: ExtURIFutureMetadata, Rvb: Rvb{ - I: rvbIdx, + I: location.maxRdRichValueIndex, }, }, }, @@ -353,7 +504,6 @@ func (f *File) writeMetadata() error { metadata.FutureMetadata[0].Name = "XLRICHVALUE" metadata.XmlnsXlrd = "http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" metadata.Xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" - // fmt.Println(metadata) xmlData, err := xml.Marshal(metadata) if err != nil { return err @@ -402,82 +552,163 @@ func (f *File) writeSheetData(sheet, cell string) error { c.Vm = &vmValueUint c.V = "#VALUE!" c.T = "e" - // fmt.Println(ws.SheetData) return nil } func (f *File) writeSpbData(entity Entity) error { - if entity.Provider.Description != "" { + + properties := entity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) + } + sort.Strings(keys) + f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBag, []byte(xml.Header+templateSpbData)) + + richDataSpbs, err := f.richDataSpbReader() + if err != nil { + return err + } + + if entity.Provider.Description != "" || entity.Layouts.Card.SubTitle.Property != "" || entity.Layouts.Card.Title.Property != "" { f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBag, []byte(xml.Header+templateSpbData)) - richDataSpbs, err := f.richDataSpbReader() - if err != nil { - return err - } - richDataSpbStructure, err := f.richDataSpbStructureReader() - if err != nil { - return err - } + if entity.Layouts.Card.Title.Property != "" || entity.Layouts.Card.SubTitle.Property != "" { + titlesSpb := xlsxRichDataSpb{ + S: location.spbStructureIndex, + } + if entity.Layouts.Card.Title.Property != "" { + titlesSpb.V = append(titlesSpb.V, entity.Layouts.Card.Title.Property) + } + if entity.Layouts.Card.SubTitle.Property != "" { + titlesSpb.V = append(titlesSpb.V, entity.Layouts.Card.SubTitle.Property) + } - providerSpb := xlsxRichDataSpb{ - S: len(richDataSpbStructure.S), - V: []string{entity.Provider.Description}, + richDataSpbs.SpbData.Spb = append(richDataSpbs.SpbData.Spb, titlesSpb) + location.spbStructureIndex++ + richDataSpbs.SpbData.Count++ } - richDataSpbs.SpbData.Spb = append(richDataSpbs.SpbData.Spb, providerSpb) - richDataSpbs.SpbData.Count++ - xmlData, err := xml.Marshal(richDataSpbs) - if err != nil { - return err + if entity.Provider.Description != "" { + + providerSpb := xlsxRichDataSpb{ + S: location.spbStructureIndex, + V: []string{entity.Provider.Description}, + } + location.spbStructureIndex++ + + richDataSpbs.SpbData.Spb = append(richDataSpbs.SpbData.Spb, providerSpb) + richDataSpbs.SpbData.Count++ } - xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) - f.saveFileList(defaultXMLRichDataSupportingPropertyBag, xmlData) } + + xmlData, err := xml.Marshal(richDataSpbs) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) + f.saveFileList(defaultXMLRichDataSupportingPropertyBag, xmlData) + return nil } func (f *File) writeSpbStructure(entity Entity) error { - if entity.Provider.Description != "" { - f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBagStructure, []byte(xml.Header+templateSpbStructure)) - richDataSpbStructure, err := f.richDataSpbStructureReader() - if err != nil { - return err - } + properties := entity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) + } + sort.Strings(keys) - providerSpbStructureKey := xlsxRichDataSpbStructureKey{ - N: "name", - T: "s", + f.checkOrCreateXML(defaultXMLRichDataSupportingPropertyBagStructure, []byte(xml.Header+templateSpbStructure)) + richDataSpbStructure, err := f.richDataSpbStructureReader() + if err != nil { + return err + } + + if entity.Provider.Description != "" || entity.Layouts.Card.SubTitle.Property != "" || entity.Layouts.Card.Title.Property != "" { + + spbStructure := xlsxRichDataSpbStructure{} + + if entity.Layouts.Card.Title.Property != "" || entity.Layouts.Card.SubTitle.Property != "" { + + if entity.Layouts.Card.Title.Property != "" { + titleSpbStructureKey := xlsxRichDataSpbStructureKey{ + N: "TitleProperty", + T: "s", + } + spbStructure.K = append(spbStructure.K, titleSpbStructureKey) + } + + if entity.Layouts.Card.SubTitle.Property != "" { + subtitleSpbStructureKey := xlsxRichDataSpbStructureKey{ + N: "SubTitleProperty", + T: "s", + } + spbStructure.K = append(spbStructure.K, subtitleSpbStructureKey) + } + + richDataSpbStructure.S = append(richDataSpbStructure.S, spbStructure) + richDataSpbStructure.Count++ } - providerSpbStructure := xlsxRichDataSpbStructure{} - providerSpbStructure.K = append(providerSpbStructure.K, providerSpbStructureKey) + if entity.Provider.Description != "" { + + providerSpbStructureKey := xlsxRichDataSpbStructureKey{ + N: "name", + T: "s", + } + + providerSpbStructure := xlsxRichDataSpbStructure{} + providerSpbStructure.K = append(providerSpbStructure.K, providerSpbStructureKey) - richDataSpbStructure.S = append(richDataSpbStructure.S, providerSpbStructure) - richDataSpbStructure.Count++ - xmlData, err := xml.Marshal(richDataSpbStructure) - if err != nil { - return err + richDataSpbStructure.S = append(richDataSpbStructure.S, providerSpbStructure) + richDataSpbStructure.Count++ } - xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) - f.saveFileList(defaultXMLRichDataSupportingPropertyBagStructure, xmlData) } + + xmlData, err := xml.Marshal(richDataSpbStructure) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) + f.saveFileList(defaultXMLRichDataSupportingPropertyBagStructure, xmlData) return nil } -func writeJSONToFile(data interface{}, filename string) error { - // Open a file for writing (create if not exists, truncate if exists) - file, err := os.Create(filename) +func (f *File) writeRichStyles(entity Entity) error { + f.checkOrCreateXML(defaultXMLRichDataRichStyles, []byte(xml.Header+templateRichStyles)) + rdRichStyles, err := f.richDataStyleReader() if err != nil { return err } - defer file.Close() - // Encode the data to JSON and write it to the file - encoder := json.NewEncoder(file) - if err := encoder.Encode(data); err != nil { - return err + properties := entity.Properties + keys := make([]string, 0, len(properties)) + for key := range properties { + keys = append(keys, key) } + sort.Strings(keys) + for _, key := range keys { + propertyMap := properties[key].(map[string]interface{}) + if propertyMap["type"] == "FormattedNumber" { + newRpv := Rpv{ + I: "0", + Text: propertyMap["numberFormat"].(string), + } + newRichSty := RSty{} + newRichSty.Rpv = newRpv + rdRichStyles.RichStyles.RSty = append(rdRichStyles.RichStyles.RSty, newRichSty) + } + } + fmt.Println(rdRichStyles) + xmlData, err := xml.Marshal(rdRichStyles) + if err != nil { + return err + } + xmlData = bytes.ReplaceAll(xmlData, []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2" xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`), []byte(`xmlns="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2"`)) + f.saveFileList(defaultXMLRichDataRichStyles, xmlData) return nil } diff --git a/excelize.go b/excelize.go index 98dbd7e932..50b2f4ba90 100644 --- a/excelize.go +++ b/excelize.go @@ -674,6 +674,15 @@ func (f *File) richDataSpbStructureReader() (*xlsxRichDataSpbStructures, error) return &richDataSpbStructure, nil } +func (f *File) richDataStyleReader() (*RichStyleSheet, error) { + var richDataStyles RichStyleSheet + if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataRichStyles)))). + Decode(&richDataStyles); err != nil && err != io.EOF { + return &richDataStyles, err + } + return &richDataStyles, nil +} + func (f *File) richDataArrayReader() (*xlsxRichValueArrayData, error) { var richDataArray xlsxRichValueArrayData if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLRichDataArray)))). diff --git a/excelize_test.go b/excelize_test.go index 9e4a7fea7c..ace4bffa2c 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -1768,78 +1768,3 @@ func TestEntityAndCellWriter(t *testing.T) { } } - -func TestMultipleEntityWriter(t *testing.T) { - jsonFile, err := os.Open("test/testEntity.json") - if err != nil { - assert.NoError(t, err) - } - defer jsonFile.Close() - - byteValue, _ := io.ReadAll(jsonFile) - - f := NewFile() - defer func() { - if err := f.Close(); err != nil { - assert.NoError(t, err) - } - }() - - index, err := f.NewSheet("Sheet1") - if err != nil { - assert.NoError(t, err) - return - } - f.SetActiveSheet(index) - - err = f.AddEntity("Sheet1", "A1", byteValue) - if err != nil { - assert.NoError(t, err) - } - err = f.AddEntity("Sheet1", "A2", byteValue) - if err != nil { - assert.NoError(t, err) - } - if err := f.SaveAs("test/TestEntity.xlsx"); err != nil { - assert.NoError(t, err) - } - -} - -func TestOverwriteEntityWriter(t *testing.T) { - jsonFile, err := os.Open("test/testEntity.json") - if err != nil { - assert.NoError(t, err) - } - defer jsonFile.Close() - - byteValue, _ := io.ReadAll(jsonFile) - - f := NewFile() - defer func() { - if err := f.Close(); err != nil { - assert.NoError(t, err) - } - }() - - index, err := f.NewSheet("Sheet1") - if err != nil { - assert.NoError(t, err) - return - } - f.SetActiveSheet(index) - - err = f.AddEntity("Sheet1", "A1", byteValue) - if err != nil { - assert.NoError(t, err) - } - err = f.AddEntity("Sheet1", "A1", byteValue) - if err != nil { - assert.NoError(t, err) - } - - if err := f.SaveAs("test/TestEntity.xlsx"); err != nil { - assert.NoError(t, err) - } - -} diff --git a/templates.go b/templates.go index abb2ee9e63..82a6ed621c 100644 --- a/templates.go +++ b/templates.go @@ -536,3 +536,4 @@ const templateSpbStructure = ` ` +const templateRichStyles = `` diff --git a/test/testEntity.json b/test/testEntity.json index 262d7348fb..80b32fc7df 100644 --- a/test/testEntity.json +++ b/test/testEntity.json @@ -7,6 +7,42 @@ "basicValue": 29253, "numberFormat": "yyyy-mm-dd" }, + "Items": { + "type": "Array", + "elements": [ + [ + { "type": "String", "basicValue": "Thomas" }, + { "type": "String", "basicValue": "Scholtz" }, + { + "type": "FormattedNumber", + "basicValue": 8.03, + "numberFormat": "$0.0" + } + ], + [ + { "type": "String", "basicValue": "James" }, + { "type": "String", "basicValue": "Spanjaard" }, + { + "type": "FormattedNumber", + "basicValue": 28.3, + "numberFormat": "$0.0" + } + ] + ] + }, + "Items2": { + "type": "Array", + "elements": [ + [ + { "type": "String", "basicValue": "Raymond" }, + { "type": "String", "basicValue": "Mendoza" } + ], + [ + { "type": "String", "basicValue": "Mary" }, + { "type": "String", "basicValue": "James" } + ] + ] + }, "Owner": { "type": "String", "basicValue": "Jan Krynauw" }, "Price": { "type": "FormattedNumber", @@ -18,7 +54,15 @@ "text": "Another one", "properties": { "Key 1": { "type": "String", "basicValue": "Value 1" }, - "Key 2": { "type": "String", "basicValue": "Value 2" } + "Key 2": { "type": "String", "basicValue": "Value 2" }, + "Sub Properties A": { + "type": "Entity", + "text": "Another one", + "properties": { + "Key 1": { "type": "String", "basicValue": "Value 1" }, + "Key 2": { "type": "String", "basicValue": "Value 2" } + } + } } }, "Total Amount": { "type": "Double", "basicValue": 7777.77 }, diff --git a/xmlMetaData.go b/xmlMetaData.go index cfc100e109..c3cb35b777 100644 --- a/xmlMetaData.go +++ b/xmlMetaData.go @@ -143,7 +143,7 @@ type xlsxRichValueData struct { type xlsxRichValue struct { S int `xml:"s,attr"` V []string `xml:"v"` - Fb string `xml:"fb,omitempty"` + Fb float64 `xml:"fb,omitempty"` } // xlsxRichValueRels directly maps the richValueRels element. This element that @@ -314,7 +314,7 @@ type RichStyles struct { // RSty struct is for the elements within . type RSty struct { Text string `xml:",chardata"` - Dxfid string `xml:"dxfid,attr"` + Dxfid int `xml:"dxfid,attr"` Rpv Rpv `xml:"rpv"` }