130 lines
3.5 KiB
Go
130 lines
3.5 KiB
Go
package xlsx
|
|
|
|
type plainTextOrRichText struct {
|
|
plainText string
|
|
isRichText bool
|
|
richText []RichTextRun
|
|
}
|
|
|
|
type RefTable struct {
|
|
indexedStrings []plainTextOrRichText
|
|
knownStrings map[string]int
|
|
knownRichTexts map[string][]int
|
|
isWrite bool
|
|
}
|
|
|
|
// NewSharedStringRefTable creates a new, empty RefTable.
|
|
func NewSharedStringRefTable() *RefTable {
|
|
rt := RefTable{}
|
|
rt.knownStrings = make(map[string]int)
|
|
rt.knownRichTexts = make(map[string][]int)
|
|
return &rt
|
|
}
|
|
|
|
// MakeSharedStringRefTable takes an xlsxSST struct and converts
|
|
// it's contents to an slice of strings used to refer to string values
|
|
// by numeric index - this is the model used within XLSX worksheet (a
|
|
// numeric reference is stored to a shared cell value).
|
|
func MakeSharedStringRefTable(source *xlsxSST) *RefTable {
|
|
reftable := NewSharedStringRefTable()
|
|
reftable.isWrite = false
|
|
for _, si := range source.SI {
|
|
if len(si.R) > 0 {
|
|
richText := xmlToRichText(si.R)
|
|
reftable.AddRichText(richText)
|
|
} else {
|
|
reftable.AddString(si.T.getText())
|
|
}
|
|
}
|
|
return reftable
|
|
}
|
|
|
|
// makeXlsxSST takes a RefTable and returns and
|
|
// equivalent xlsxSST representation.
|
|
func (rt *RefTable) makeXLSXSST() xlsxSST {
|
|
sst := xlsxSST{}
|
|
sst.Count = len(rt.indexedStrings)
|
|
sst.UniqueCount = sst.Count
|
|
for _, ref := range rt.indexedStrings {
|
|
si := xlsxSI{}
|
|
if ref.isRichText {
|
|
si.R = richTextToXml(ref.richText)
|
|
} else {
|
|
si.T = &xlsxT{Text: ref.plainText}
|
|
}
|
|
sst.SI = append(sst.SI, si)
|
|
}
|
|
return sst
|
|
}
|
|
|
|
// ResolveSharedString looks up a string value or the rich text by numeric index from
|
|
// a provided reference table (just a slice of strings in the correct order).
|
|
// If the rich text was found, non-empty slice will be returned in richText.
|
|
// This function only exists to provide clarity of purpose via it's name.
|
|
func (rt *RefTable) ResolveSharedString(index int) (plainText string, richText []RichTextRun) {
|
|
ptrt := rt.indexedStrings[index]
|
|
if ptrt.isRichText {
|
|
richText = ptrt.richText
|
|
} else {
|
|
plainText = ptrt.plainText
|
|
}
|
|
return
|
|
}
|
|
|
|
// AddString adds a string to the reference table and return it's
|
|
// numeric index. If the string already exists then it simply returns
|
|
// the existing index.
|
|
func (rt *RefTable) AddString(str string) int {
|
|
if rt.isWrite {
|
|
index, ok := rt.knownStrings[str]
|
|
if ok {
|
|
return index
|
|
}
|
|
}
|
|
ptrt := plainTextOrRichText{plainText: str, isRichText: false}
|
|
rt.indexedStrings = append(rt.indexedStrings, ptrt)
|
|
index := len(rt.indexedStrings) - 1
|
|
rt.knownStrings[str] = index
|
|
return index
|
|
}
|
|
|
|
// AddRichText adds a set of rich text to the reference table and return it's
|
|
// numeric index. If a set of rich text already exists then it simply returns
|
|
// the existing index.
|
|
func (rt *RefTable) AddRichText(r []RichTextRun) int {
|
|
plain := richTextToPlainText(r)
|
|
if rt.isWrite {
|
|
indices, ok := rt.knownRichTexts[plain]
|
|
if ok {
|
|
for _, index := range indices {
|
|
if areRichTextsEqual(rt.indexedStrings[index].richText, r) {
|
|
return index
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ptrt := plainTextOrRichText{isRichText: true}
|
|
ptrt.richText = append(ptrt.richText, r...)
|
|
rt.indexedStrings = append(rt.indexedStrings, ptrt)
|
|
index := len(rt.indexedStrings) - 1
|
|
rt.knownRichTexts[plain] = append(rt.knownRichTexts[plain], index)
|
|
return index
|
|
}
|
|
|
|
func areRichTextsEqual(r1 []RichTextRun, r2 []RichTextRun) bool {
|
|
if len(r1) != len(r2) {
|
|
return false
|
|
}
|
|
for i, rt1 := range r1 {
|
|
rt2 := r2[i]
|
|
if !rt1.Equals(&rt2) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (rt *RefTable) Length() int {
|
|
return len(rt.indexedStrings)
|
|
}
|