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..355504640f
--- /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 != 0 {
+ 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 != 0 {
+ 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..bdb2b492d1
--- /dev/null
+++ b/entity_write.go
@@ -0,0 +1,714 @@
+package excelize
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type Location struct {
+ maxRdRichValueStructureIndex int
+ maxRdRichValueIndex int
+ spbStructureIndex int
+ arrayCount int
+ spbDataIndex int
+}
+
+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.writeSheetData(sheet, cell)
+ if err != nil {
+ return err
+ }
+
+ var entity Entity
+ err = json.Unmarshal(entityData, &entity)
+ if err != nil {
+ return err
+ }
+
+ err = f.writeRdRichValueStructure(entity)
+ if err != nil {
+ return err
+ }
+ err = f.writeRdRichValue(entity)
+ if err != nil {
+ return err
+ }
+ err = f.writeMetadata()
+ if err != nil {
+ return err
+ }
+ err = f.writeSpbData(entity)
+ if err != nil {
+ return err
+ }
+ err = f.writeSpbStructure(entity)
+ if err != nil {
+ return err
+ }
+ // err = f.writeRichStyles(entity)
+ // if err != nil {
+ // return err
+ // }
+ return nil
+
+}
+
+func (f *File) writeRdRichValueStructure(entity Entity) error {
+
+ richValueStructure, err := f.richStructureReader()
+ if err != nil {
+ 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"})
+ }
+ 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)
+
+ for _, key := range keys {
+ propertyMap := properties[key].(map[string]interface{})
+ if propertyMap["type"] == "String" {
+ 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()
+ if err != nil {
+ return err
+ }
+ 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
+ }
+
+ }
+ }
+
+ newRichValueStructure := xlsxRichValueStructure{
+ T: "_entity",
+ K: newRichValueStructureKeys,
+ }
+
+ richValueStructure.S = append(richValueStructure.S, newRichValueStructure)
+ richValueStructure.Count = strconv.Itoa(len(richValueStructure.S))
+ 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) 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"})
+
+ arrayRichStructure := xlsxRichValueStructure{
+ T: "_array",
+ K: newArrayRichValueStructure,
+ }
+ return arrayRichStructure, nil
+}
+
+func (f *File) createArrayFbStructure(elements interface{}) (xlsxRichValueStructure, error) {
+ var arrayFbStructure xlsxRichValueStructure
+
+ arrayElements := elements.([]interface{})
+ for _, element_row := range arrayElements {
+ newRow := element_row.([]interface{})
+ for _, key := range newRow {
+ newMap := key.(map[string]interface{})
+
+ if newMap["type"].(string) == "FormattedNumber" {
+
+ newArrayFbStructure := []xlsxRichValueStructureKey{}
+ newArrayFbStructure = append(newArrayFbStructure, xlsxRichValueStructureKey{N: "_Format", T: "spb"})
+
+ arrayFbStructure = xlsxRichValueStructure{
+ T: "_formattednumber",
+ K: newArrayFbStructure,
+ }
+
+ }
+ }
+ }
+
+ 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)
+ if entity.Layouts.Compact.Icon != "" {
+ richDataRichValues = append(richDataRichValues, entity.Layouts.Compact.Icon)
+ }
+ if entity.Provider.Description != "" {
+
+ richDataRichValues = append(richDataRichValues, strconv.Itoa(location.spbDataIndex))
+ location.spbDataIndex++
+ }
+
+ var index 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{})
+ 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" {
+ if propertyMap["basicValue"] == true {
+ richDataRichValues = append(richDataRichValues, "1")
+ } else {
+ richDataRichValues = append(richDataRichValues, "0")
+ }
+ } else if propertyMap["type"] == "Array" {
+ richDataRichValues = append(richDataRichValues, strconv.Itoa(location.maxRdRichValueIndex))
+
+ //creating new rv for array
+ richDataRichArrayValues := []string{}
+ richDataRichArrayValues = append(richDataRichArrayValues, strconv.Itoa(location.arrayCount))
+ location.arrayCount++
+ newRichArrayValue := xlsxRichValue{
+ S: location.maxRdRichValueStructureIndex,
+ V: richDataRichArrayValues,
+ }
+ location.maxRdRichValueStructureIndex++
+
+ richValue.Rv = append(richValue.Rv, newRichArrayValue)
+ location.maxRdRichValueIndex++
+
+ //creating rdarrayfile
+
+ f.checkOrCreateXML(defaultXMLRichDataArray, []byte(xml.Header+templateRDArray))
+
+ 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{})
+
+ 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)
+
+ }
+
+ }
+ }
+
+ richDataArray, err := f.richDataArrayReader()
+ if err != nil {
+ return err
+ }
+
+ array_data := xlsxRichValuesArray{
+ R: strconv.Itoa(rows),
+ C: cols,
+ V: values_array,
+ }
+ richDataArray.A = append(richDataArray.A, array_data)
+ richDataArray.Count++
+
+ 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: location.maxRdRichValueStructureIndex,
+ V: richDataRichValues,
+ }
+ location.maxRdRichValueStructureIndex++
+
+ richValue.Rv = append(richValue.Rv, newRichValue)
+ richValue.Count = len(richValue.Rv)
+ xmlData, err := xml.Marshal(richValue)
+ if err != nil {
+ return err
+ }
+ f.saveFileList(defaultXMLRdRichValuePart, xmlData)
+ return nil
+}
+
+func (f *File) writeMetadata() error {
+ 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: location.maxRdRichValueIndex,
+ },
+ },
+ },
+ }
+ 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"
+ 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"
+ return nil
+}
+
+func (f *File) writeSpbData(entity Entity) error {
+
+ 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))
+ 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)
+ }
+
+ richDataSpbs.SpbData.Spb = append(richDataSpbs.SpbData.Spb, titlesSpb)
+ location.spbStructureIndex++
+ richDataSpbs.SpbData.Count++
+ }
+
+ 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, 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 {
+
+ properties := entity.Properties
+ keys := make([]string, 0, len(properties))
+ for key := range properties {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+
+ 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++
+ }
+
+ 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
+ }
+ 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 (f *File) writeRichStyles(entity Entity) error {
+ f.checkOrCreateXML(defaultXMLRichDataRichStyles, []byte(xml.Header+templateRichStyles))
+ rdRichStyles, err := f.richDataStyleReader()
+ 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)
+
+ 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 c46984f505..dcd6174d7e 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.
@@ -16,6 +20,7 @@ import (
"archive/zip"
"bytes"
"encoding/xml"
+ "fmt"
"io"
"os"
"path/filepath"
@@ -59,6 +64,36 @@ type File struct {
WorkBook *xlsxWorkbook
}
+type Entity struct {
+ 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
// the spreadsheet from non-UTF-8 encoding.
type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, err error)
@@ -612,6 +647,80 @@ 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) 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) 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)))).
+ Decode(&richDataArray); err != nil && err != io.EOF {
+ return &richDataArray, err
+ }
+ return &richDataArray, nil
+}
+
+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(templateRichValuetypes))
+ return nil
+}
+
+func (f *File) checkOrCreateXML(name string, defaultContent []byte) {
+ if _, ok := f.Pkg.Load(name); !ok {
+ f.Pkg.Store(name, defaultContent)
+ }
+}
+
+// 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.
func (f *File) richValueRelReader() (*xlsxRichValueRels, error) {
diff --git a/excelize_test.go b/excelize_test.go
index b689602a98..c5ecf77b01 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -1699,3 +1699,72 @@ 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)
+ }
+
+}
diff --git a/templates.go b/templates.go
index 3bf4c5fe69..82a6ed621c 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.
@@ -266,25 +267,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
@@ -499,7 +506,7 @@ var builtInDefinedNames = []string{"_xlnm.Print_Area", "_xlnm.Print_Titles", "_x
const templateDocpropsApp = `0Go Excelize`
-const templateContentTypes = ``
+const templateContentTypes = ``
const templateWorkbook = ``
@@ -507,7 +514,7 @@ const templateStyles = ``
-const templateWorkbookRels = ``
+const templateWorkbookRels = ``
const templateDocpropsCore = `xuri2006-09-16T00:00:00Z2006-09-16T00:00:00Z`
@@ -516,3 +523,17 @@ 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 = ``
+
+const templateSpbData = ``
+
+const templateSpbStructure = ``
+
+const templateRDArray = `
+`
+const templateRichStyles = ``
diff --git a/test/testEntity.json b/test/testEntity.json
new file mode 100644
index 0000000000..80b32fc7df
--- /dev/null
+++ b/test/testEntity.json
@@ -0,0 +1,79 @@
+{
+ "type": "Entity",
+ "text": "Card Top Title",
+ "properties": {
+ "Effective Date": {
+ "type": "FormattedNumber",
+ "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",
+ "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" },
+ "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 016e348674..c3cb35b777 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,7 +68,20 @@ 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 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
@@ -68,10 +105,34 @@ 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:"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
+// information for an array data
+type xlsxRichValuesArray struct {
+ R string `xml:"r,attr"`
+ C int `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 {
- 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"`
@@ -80,9 +141,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 float64 `xml:"fb,omitempty"`
}
// xlsxRichValueRels directly maps the richValueRels element. This element that
@@ -99,6 +160,170 @@ 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:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata 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,omitempty"`
+}
+
+// XlsxRichDataSupportingPropertyBags directly maps the supportingPropertyBags element that specifies supporting property bag data.
+type XlsxRichDataSupportingPropertyBags struct {
+ 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"`
+}
+
+// XlsxRichDataSpbData directly maps the spbData element that specifies supporting property bag data.
+type xlsxRichDataSpbData struct {
+ Text string `xml:",chardata"`
+ 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"`
+}
+
+// XlsxRichDataSpbStructures directly maps the spbStructures element that specifies supporting property bag structure.
+type xlsxRichDataSpbStructures struct {
+ XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 spbStructures"`
+ Text string `xml:",chardata"`
+ Xmlns string `xml:"xmlns,attr"`
+ Count int `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"`
+}
+
+type RvTypesInfo struct {
+ 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"`
+ 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:"http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2 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 int `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.