mirror of
https://github.com/unidoc/unioffice.git
synced 2025-05-10 19:29:15 +08:00
split out filename work
This commit is contained in:
parent
67d22cab80
commit
771c550c7f
13
algo/strings.go
Normal file
13
algo/strings.go
Normal file
@ -0,0 +1,13 @@
|
||||
package algo
|
||||
|
||||
func RepeatString(s string, cnt int) string {
|
||||
if cnt <= 0 {
|
||||
return ""
|
||||
}
|
||||
buf := make([]byte, len(s)*cnt)
|
||||
sb := []byte(s)
|
||||
for i := 0; i < cnt; i++ {
|
||||
copy(buf[i:], sb)
|
||||
}
|
||||
return string(buf)
|
||||
}
|
@ -57,8 +57,8 @@ func (r Relationships) FindRIDForN(i int, t string) string {
|
||||
// AddAutoRelationship adds a relationship with an automatically generated
|
||||
// filename based off of the type. It should be preferred over AddRelationship
|
||||
// to ensure consistent filenames are maintained.
|
||||
func (r Relationships) AddAutoRelationship(dt gooxml.DocType, idx int, ctype string) Relationship {
|
||||
return r.AddRelationship(gooxml.RelativeFilename(dt, ctype, idx), ctype)
|
||||
func (r Relationships) AddAutoRelationship(dt gooxml.DocType, src string, idx int, ctype string) Relationship {
|
||||
return r.AddRelationship(gooxml.RelativeFilename(dt, src, ctype, idx), ctype)
|
||||
}
|
||||
|
||||
// AddRelationship adds a relationship.
|
||||
|
@ -67,7 +67,7 @@ func New() *Document {
|
||||
d.ContentTypes.AddOverride("/word/settings.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml")
|
||||
|
||||
d.Rels = common.NewRelationships()
|
||||
d.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeDocument, gooxml.CorePropertiesType, 0), gooxml.CorePropertiesType)
|
||||
d.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeDocument, "", gooxml.CorePropertiesType, 0), gooxml.CorePropertiesType)
|
||||
d.Rels.AddRelationship("docProps/app.xml", gooxml.ExtendedPropertiesType)
|
||||
d.Rels.AddRelationship("word/document.xml", gooxml.OfficeDocumentType)
|
||||
|
||||
@ -370,8 +370,8 @@ func Read(r io.ReaderAt, size int64) (*Document, error) {
|
||||
decMap := zippkg.DecodeMap{}
|
||||
decMap.SetOnNewRelationshipFunc(doc.onNewRelationship)
|
||||
// we should discover all contents by starting with these two files
|
||||
decMap.AddTarget(zippkg.Target{Path: gooxml.ContentTypesFilename, Ifc: doc.ContentTypes.X()})
|
||||
decMap.AddTarget(zippkg.Target{Path: gooxml.BaseRelsFilename, Ifc: doc.Rels.X()})
|
||||
decMap.AddTarget(gooxml.ContentTypesFilename, doc.ContentTypes.X(), "", 0)
|
||||
decMap.AddTarget(gooxml.BaseRelsFilename, doc.Rels.X(), "", 0)
|
||||
if err := decMap.Decode(files); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -490,18 +490,18 @@ func (doc *Document) onNewRelationship(decMap *zippkg.DecodeMap, target, typ str
|
||||
switch typ {
|
||||
case gooxml.OfficeDocumentType:
|
||||
doc.x = wml.NewDocument()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.x})
|
||||
decMap.AddTarget(target, doc.x, typ, 0)
|
||||
// look for the document relationships file as well
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(target), Ifc: doc.docRels.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(target), doc.docRels.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.CorePropertiesType:
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.CoreProperties.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.CoreProperties.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.ExtendedPropertiesType:
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.AppProperties.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.AppProperties.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.ThumbnailType:
|
||||
// read our thumbnail
|
||||
@ -524,56 +524,56 @@ func (doc *Document) onNewRelationship(decMap *zippkg.DecodeMap, target, typ str
|
||||
}
|
||||
|
||||
case gooxml.SettingsType:
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.Settings.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.Settings.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.NumberingType:
|
||||
doc.Numbering = NewNumbering()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.Numbering.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.Numbering.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.StylesType:
|
||||
doc.Styles.Clear()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.Styles.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.Styles.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.HeaderType:
|
||||
hdr := wml.NewHdr()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: hdr, Index: uint32(len(doc.headers))})
|
||||
decMap.AddTarget(target, hdr, typ, uint32(len(doc.headers)))
|
||||
doc.headers = append(doc.headers, hdr)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(doc.headers))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(doc.headers))
|
||||
|
||||
case gooxml.FooterType:
|
||||
ftr := wml.NewFtr()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: ftr, Index: uint32(len(doc.footers))})
|
||||
decMap.AddTarget(target, ftr, typ, uint32(len(doc.footers)))
|
||||
doc.footers = append(doc.footers, ftr)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(doc.footers))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(doc.footers))
|
||||
|
||||
case gooxml.ThemeType:
|
||||
thm := dml.NewTheme()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: thm, Index: uint32(len(doc.themes))})
|
||||
decMap.AddTarget(target, thm, typ, uint32(len(doc.themes)))
|
||||
doc.themes = append(doc.themes, thm)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(doc.themes))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(doc.themes))
|
||||
|
||||
case gooxml.WebSettingsType:
|
||||
doc.webSettings = wml.NewWebSettings()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.webSettings})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.webSettings, typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.FontTableType:
|
||||
doc.fontTable = wml.NewFonts()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.fontTable})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.fontTable, typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.EndNotesType:
|
||||
doc.endNotes = wml.NewEndnotes()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.endNotes})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.endNotes, typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.FootNotesType:
|
||||
doc.footNotes = wml.NewFootnotes()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: doc.footNotes})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, doc.footNotes, typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.ImageType:
|
||||
for i, f := range files {
|
||||
|
114
filenames.go
114
filenames.go
@ -10,6 +10,9 @@ package gooxml
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"baliance.com/gooxml/algo"
|
||||
)
|
||||
|
||||
// Common filenames used in zip packages.
|
||||
@ -29,89 +32,36 @@ const (
|
||||
DocTypePresentation
|
||||
)
|
||||
|
||||
// RelativeFilename returns a filename relative to where it is normally
|
||||
// referenced from a relationships file. Index is used in some cases for files
|
||||
// which there may be more than one of (e.g. worksheets/drawings/charts)
|
||||
func RelativeFilename(dt DocType, typ string, index int) string {
|
||||
switch typ {
|
||||
case CorePropertiesType:
|
||||
return "docProps/core.xml"
|
||||
case ExtendedPropertiesType:
|
||||
return "docProps/app.xml"
|
||||
case ThumbnailType:
|
||||
return "docProps/thumbnail.jpeg"
|
||||
|
||||
case StylesType:
|
||||
return "styles.xml"
|
||||
case ChartType, ChartContentType:
|
||||
return fmt.Sprintf("../charts/chart%d.xml", index)
|
||||
case DrawingType, DrawingContentType:
|
||||
return fmt.Sprintf("../drawings/drawing%d.xml", index)
|
||||
case CommentsType, CommentsContentType:
|
||||
return fmt.Sprintf("../comments%d.xml", index)
|
||||
|
||||
case VMLDrawingType, VMLDrawingContentType:
|
||||
return fmt.Sprintf("../drawings/vmlDrawing%d.vml", index)
|
||||
|
||||
case TableType, TableContentType:
|
||||
return fmt.Sprintf("../tables/table%d.xml", index)
|
||||
|
||||
case ThemeType, ThemeContentType:
|
||||
return fmt.Sprintf("theme/theme%d.xml", index)
|
||||
case OfficeDocumentType:
|
||||
switch dt {
|
||||
case DocTypeSpreadsheet:
|
||||
return "xl/workbook.xml"
|
||||
case DocTypeDocument:
|
||||
return "word/document.xml"
|
||||
default:
|
||||
log.Printf("unsupported type %s pair and %v", typ, dt)
|
||||
}
|
||||
|
||||
case ImageType:
|
||||
switch dt {
|
||||
case DocTypeSpreadsheet:
|
||||
return fmt.Sprintf("media/image%d.png", index)
|
||||
case DocTypeDocument:
|
||||
return fmt.Sprintf("media/image%d.png", index)
|
||||
default:
|
||||
log.Printf("unsupported type %s pair and %v", typ, dt)
|
||||
}
|
||||
|
||||
// SML
|
||||
case WorksheetType, WorksheetContentType:
|
||||
return fmt.Sprintf("worksheets/sheet%d.xml", index)
|
||||
|
||||
case PivotTableType:
|
||||
return fmt.Sprintf("../pivotTables/pivotTable%d.xml", index)
|
||||
case PivotCacheDefinitionType:
|
||||
return fmt.Sprintf("../pivotCache/pivotCacheDefinition%d.xml", index)
|
||||
case PivotCacheRecordsType:
|
||||
return fmt.Sprintf("../pivotCache/pivotCacheRecords%d.xml", index)
|
||||
case SharedStingsType, SharedStringsContentType:
|
||||
return "sharedStrings.xml"
|
||||
|
||||
// WML
|
||||
case FontTableType:
|
||||
return "fontTable.xml"
|
||||
case EndNotesType:
|
||||
return "endnotes.xml"
|
||||
case FootNotesType:
|
||||
return "footnotes.xml"
|
||||
case NumberingType:
|
||||
return "numbering.xml"
|
||||
case WebSettingsType:
|
||||
return "webSettings.xml"
|
||||
case SettingsType:
|
||||
return "settings.xml"
|
||||
case HeaderType:
|
||||
return fmt.Sprintf("header%d.xml", index)
|
||||
case FooterType:
|
||||
return fmt.Sprintf("footer%d.xml", index)
|
||||
default:
|
||||
log.Printf("unsupported type %s", typ)
|
||||
// RelativeFilename returns a filename relative to the source file referenced
|
||||
// from a relationships file. Index is used in some cases for files which there
|
||||
// may be more than one of (e.g. worksheets/drawings/charts)
|
||||
func RelativeFilename(dt DocType, relToTyp, typ string, index int) string {
|
||||
orig := AbsoluteFilename(dt, typ, index)
|
||||
if relToTyp == "" {
|
||||
return orig
|
||||
}
|
||||
return ""
|
||||
|
||||
relTo := AbsoluteFilename(dt, relToTyp, index)
|
||||
relToSp := strings.Split(relTo, "/")
|
||||
origSp := strings.Split(orig, "/")
|
||||
|
||||
// determine how many segments match
|
||||
matching := 0
|
||||
for i := 0; i < len(relToSp); i++ {
|
||||
if relToSp[i] == origSp[i] {
|
||||
matching++
|
||||
}
|
||||
if i+1 == len(origSp) {
|
||||
break
|
||||
}
|
||||
}
|
||||
relToSp = relToSp[matching:]
|
||||
origSp = origSp[matching:]
|
||||
nm := len(relToSp) - 1
|
||||
if nm > 0 {
|
||||
return algo.RepeatString("../", nm) + strings.Join(origSp, "/")
|
||||
}
|
||||
return strings.Join(origSp, "/")
|
||||
}
|
||||
|
||||
// AbsoluteFilename returns the full path to a file from the root of the zip
|
||||
|
@ -14,31 +14,26 @@ func TestWMLFilenames(t *testing.T) {
|
||||
td := []struct {
|
||||
Idx int
|
||||
Type string
|
||||
ExpRel string
|
||||
ExpAbs string
|
||||
}{
|
||||
{0, gooxml.CorePropertiesType, "docProps/core.xml", "docProps/core.xml"},
|
||||
{0, gooxml.ExtendedPropertiesType, "docProps/app.xml", "docProps/app.xml"},
|
||||
{0, gooxml.ThumbnailType, "docProps/thumbnail.jpeg", "docProps/thumbnail.jpeg"},
|
||||
{0, gooxml.StylesType, "styles.xml", "word/styles.xml"},
|
||||
{0, gooxml.CorePropertiesType, "docProps/core.xml"},
|
||||
{0, gooxml.ExtendedPropertiesType, "docProps/app.xml"},
|
||||
{0, gooxml.ThumbnailType, "docProps/thumbnail.jpeg"},
|
||||
{0, gooxml.StylesType, "word/styles.xml"},
|
||||
|
||||
{0, gooxml.OfficeDocumentType, "word/document.xml", "word/document.xml"},
|
||||
{0, gooxml.FontTableType, "fontTable.xml", "word/fontTable.xml"},
|
||||
{0, gooxml.EndNotesType, "endnotes.xml", "word/endnotes.xml"},
|
||||
{0, gooxml.FootNotesType, "footnotes.xml", "word/footnotes.xml"},
|
||||
{0, gooxml.NumberingType, "numbering.xml", "word/numbering.xml"},
|
||||
{0, gooxml.WebSettingsType, "webSettings.xml", "word/webSettings.xml"},
|
||||
{0, gooxml.SettingsType, "settings.xml", "word/settings.xml"},
|
||||
{23, gooxml.HeaderType, "header23.xml", "word/header23.xml"},
|
||||
{15, gooxml.FooterType, "footer15.xml", "word/footer15.xml"},
|
||||
{1, gooxml.ThemeType, "theme/theme1.xml", "word/theme/theme1.xml"},
|
||||
{0, gooxml.OfficeDocumentType, "word/document.xml"},
|
||||
{0, gooxml.FontTableType, "word/fontTable.xml"},
|
||||
{0, gooxml.EndNotesType, "word/endnotes.xml"},
|
||||
{0, gooxml.FootNotesType, "word/footnotes.xml"},
|
||||
{0, gooxml.NumberingType, "word/numbering.xml"},
|
||||
{0, gooxml.WebSettingsType, "word/webSettings.xml"},
|
||||
{0, gooxml.SettingsType, "word/settings.xml"},
|
||||
{23, gooxml.HeaderType, "word/header23.xml"},
|
||||
{15, gooxml.FooterType, "word/footer15.xml"},
|
||||
{1, gooxml.ThemeType, "word/theme/theme1.xml"},
|
||||
}
|
||||
for _, tc := range td {
|
||||
rel := gooxml.RelativeFilename(gooxml.DocTypeDocument, tc.Type, tc.Idx)
|
||||
abs := gooxml.AbsoluteFilename(gooxml.DocTypeDocument, tc.Type, tc.Idx)
|
||||
if rel != tc.ExpRel {
|
||||
t.Errorf("expected relative filename of %s for document %s/%d, got %s", tc.ExpRel, tc.Type, tc.Idx, rel)
|
||||
}
|
||||
if abs != tc.ExpAbs {
|
||||
t.Errorf("expected absolute filename of %s for document %s/%d, got %s", tc.ExpAbs, tc.Type, tc.Idx, abs)
|
||||
}
|
||||
@ -49,33 +44,28 @@ func TestSMLFilenames(t *testing.T) {
|
||||
td := []struct {
|
||||
Idx int
|
||||
Type string
|
||||
ExpRel string
|
||||
ExpAbs string
|
||||
}{
|
||||
{0, gooxml.CorePropertiesType, "docProps/core.xml", "docProps/core.xml"},
|
||||
{0, gooxml.ExtendedPropertiesType, "docProps/app.xml", "docProps/app.xml"},
|
||||
{0, gooxml.ThumbnailType, "docProps/thumbnail.jpeg", "docProps/thumbnail.jpeg"},
|
||||
{0, gooxml.StylesType, "styles.xml", "xl/styles.xml"},
|
||||
{0, gooxml.CorePropertiesType, "docProps/core.xml"},
|
||||
{0, gooxml.ExtendedPropertiesType, "docProps/app.xml"},
|
||||
{0, gooxml.ThumbnailType, "docProps/thumbnail.jpeg"},
|
||||
{0, gooxml.StylesType, "xl/styles.xml"},
|
||||
|
||||
{0, gooxml.OfficeDocumentType, "xl/workbook.xml", "xl/workbook.xml"},
|
||||
{15, gooxml.ChartType, "../charts/chart15.xml", "xl/charts/chart15.xml"},
|
||||
{12, gooxml.DrawingType, "../drawings/drawing12.xml", "xl/drawings/drawing12.xml"},
|
||||
{13, gooxml.TableType, "../tables/table13.xml", "xl/tables/table13.xml"},
|
||||
{2, gooxml.CommentsType, "../comments2.xml", "xl/comments2.xml"},
|
||||
{15, gooxml.WorksheetType, "worksheets/sheet15.xml", "xl/worksheets/sheet15.xml"},
|
||||
{2, gooxml.VMLDrawingType, "../drawings/vmlDrawing2.vml", "xl/drawings/vmlDrawing2.vml"},
|
||||
{0, gooxml.SharedStingsType, "sharedStrings.xml", "xl/sharedStrings.xml"},
|
||||
{1, gooxml.ThemeType, "theme/theme1.xml", "xl/theme/theme1.xml"},
|
||||
{2, gooxml.PivotTableType, "../pivotTables/pivotTable2.xml", "xl/pivotTables/pivotTable2.xml"},
|
||||
{3, gooxml.PivotCacheDefinitionType, "../pivotCache/pivotCacheDefinition3.xml", "xl/pivotCache/pivotCacheDefinition3.xml"},
|
||||
{4, gooxml.PivotCacheRecordsType, "../pivotCache/pivotCacheRecords4.xml", "xl/pivotCache/pivotCacheRecords4.xml"},
|
||||
{0, gooxml.OfficeDocumentType, "xl/workbook.xml"},
|
||||
{15, gooxml.ChartType, "xl/charts/chart15.xml"},
|
||||
{12, gooxml.DrawingType, "xl/drawings/drawing12.xml"},
|
||||
{13, gooxml.TableType, "xl/tables/table13.xml"},
|
||||
{2, gooxml.CommentsType, "xl/comments2.xml"},
|
||||
{15, gooxml.WorksheetType, "xl/worksheets/sheet15.xml"},
|
||||
{2, gooxml.VMLDrawingType, "xl/drawings/vmlDrawing2.vml"},
|
||||
{0, gooxml.SharedStingsType, "xl/sharedStrings.xml"},
|
||||
{1, gooxml.ThemeType, "xl/theme/theme1.xml"},
|
||||
{2, gooxml.PivotTableType, "xl/pivotTables/pivotTable2.xml"},
|
||||
{3, gooxml.PivotCacheDefinitionType, "xl/pivotCache/pivotCacheDefinition3.xml"},
|
||||
{4, gooxml.PivotCacheRecordsType, "xl/pivotCache/pivotCacheRecords4.xml"},
|
||||
}
|
||||
for _, tc := range td {
|
||||
rel := gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, tc.Type, tc.Idx)
|
||||
abs := gooxml.AbsoluteFilename(gooxml.DocTypeSpreadsheet, tc.Type, tc.Idx)
|
||||
if rel != tc.ExpRel {
|
||||
t.Errorf("expected relative filename of %s for document %s/%d, got %s", tc.ExpRel, tc.Type, tc.Idx, rel)
|
||||
}
|
||||
if abs != tc.ExpAbs {
|
||||
t.Errorf("expected absolute filename of %s for document %s/%d, got %s", tc.ExpAbs, tc.Type, tc.Idx, abs)
|
||||
}
|
||||
|
@ -45,10 +45,11 @@ func (d Drawing) AddChart(at AnchorType) (chart.Chart, Anchor) {
|
||||
d.wb.ContentTypes.AddOverride(fn, gooxml.ChartContentType)
|
||||
|
||||
var chartID string
|
||||
|
||||
// add relationship from drawing to the chart
|
||||
for i, dr := range d.wb.drawings {
|
||||
if dr == d.x {
|
||||
fn := gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.ChartType, len(d.wb.charts))
|
||||
fn := gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.DrawingType, gooxml.ChartType, len(d.wb.charts))
|
||||
rel := d.wb.drawingRels[i].AddRelationship(fn, gooxml.ChartType)
|
||||
chartID = rel.ID()
|
||||
break
|
||||
|
@ -24,10 +24,11 @@ func New() *Workbook {
|
||||
|
||||
wb.Rels = common.NewRelationships()
|
||||
wb.wbRels = common.NewRelationships()
|
||||
wb.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.ExtendedPropertiesType, 0), gooxml.ExtendedPropertiesType)
|
||||
wb.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.CorePropertiesType, 0), gooxml.CorePropertiesType)
|
||||
wb.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.OfficeDocumentType, 0), gooxml.OfficeDocumentType)
|
||||
wb.wbRels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.StylesType, 0), gooxml.StylesType)
|
||||
|
||||
wb.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, "", gooxml.ExtendedPropertiesType, 0), gooxml.ExtendedPropertiesType)
|
||||
wb.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, "", gooxml.CorePropertiesType, 0), gooxml.CorePropertiesType)
|
||||
wb.Rels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, "", gooxml.OfficeDocumentType, 0), gooxml.OfficeDocumentType)
|
||||
wb.wbRels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.OfficeDocumentType, gooxml.StylesType, 0), gooxml.StylesType)
|
||||
|
||||
wb.ContentTypes = common.NewContentTypes()
|
||||
wb.ContentTypes.AddDefault("vml", gooxml.VMLDrawingContentType)
|
||||
@ -36,7 +37,7 @@ func New() *Workbook {
|
||||
|
||||
wb.SharedStrings = NewSharedStrings()
|
||||
wb.ContentTypes.AddOverride(gooxml.AbsoluteFilename(gooxml.DocTypeSpreadsheet, gooxml.SharedStingsType, 0), gooxml.SharedStringsContentType)
|
||||
wb.wbRels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.SharedStingsType, 0), gooxml.SharedStingsType)
|
||||
wb.wbRels.AddRelationship(gooxml.RelativeFilename(gooxml.DocTypeSpreadsheet, gooxml.OfficeDocumentType, gooxml.SharedStingsType, 0), gooxml.SharedStingsType)
|
||||
|
||||
return wb
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ func Read(r io.ReaderAt, size int64) (*Workbook, error) {
|
||||
decMap := zippkg.DecodeMap{}
|
||||
decMap.SetOnNewRelationshipFunc(wb.onNewRelationship)
|
||||
// we should discover all contents by starting with these two files
|
||||
decMap.AddTarget(zippkg.Target{Path: gooxml.ContentTypesFilename, Ifc: wb.ContentTypes.X()})
|
||||
decMap.AddTarget(zippkg.Target{Path: gooxml.BaseRelsFilename, Ifc: wb.Rels.X()})
|
||||
decMap.AddTarget(gooxml.ContentTypesFilename, wb.ContentTypes.X(), "", 0)
|
||||
decMap.AddTarget(gooxml.BaseRelsFilename, wb.Rels.X(), "", 0)
|
||||
if err := decMap.Decode(files); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ type Sheet struct {
|
||||
x *sml.Worksheet
|
||||
}
|
||||
|
||||
func (s Sheet) IsValid() bool {
|
||||
return s.x != nil
|
||||
}
|
||||
|
||||
// X returns the inner wrapped XML type.
|
||||
func (s Sheet) X() *sml.Worksheet {
|
||||
return s.x
|
||||
@ -232,11 +236,12 @@ func (s Sheet) SetDrawing(d Drawing) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// add relationship from drawing to the sheet
|
||||
var drawingID string
|
||||
for i, dr := range d.wb.drawings {
|
||||
if dr == d.x {
|
||||
rel := rel.AddAutoRelationship(gooxml.DocTypeSpreadsheet, i+1, gooxml.DrawingType)
|
||||
rel := rel.AddAutoRelationship(gooxml.DocTypeSpreadsheet, gooxml.WorksheetType, i+1, gooxml.DrawingType)
|
||||
drawingID = rel.ID()
|
||||
break
|
||||
}
|
||||
@ -453,12 +458,12 @@ func (s Sheet) Comments() Comments {
|
||||
if wks == s.x {
|
||||
if s.w.comments[i] == nil {
|
||||
s.w.comments[i] = sml.NewComments()
|
||||
s.w.xwsRels[i].AddAutoRelationship(gooxml.DocTypeSpreadsheet, i+1, gooxml.CommentsType)
|
||||
s.w.xwsRels[i].AddAutoRelationship(gooxml.DocTypeSpreadsheet, gooxml.WorksheetType, i+1, gooxml.CommentsType)
|
||||
s.w.ContentTypes.AddOverride(gooxml.AbsoluteFilename(gooxml.DocTypeSpreadsheet, gooxml.CommentsType, i+1), gooxml.CommentsContentType)
|
||||
}
|
||||
if len(s.w.vmlDrawings) == 0 {
|
||||
s.w.vmlDrawings = append(s.w.vmlDrawings, vmldrawing.NewCommentDrawing())
|
||||
vmlID := s.w.xwsRels[i].AddAutoRelationship(gooxml.DocTypeSpreadsheet, 1, gooxml.VMLDrawingType)
|
||||
vmlID := s.w.xwsRels[i].AddAutoRelationship(gooxml.DocTypeSpreadsheet, gooxml.WorksheetType, 1, gooxml.VMLDrawingType)
|
||||
if s.x.LegacyDrawing == nil {
|
||||
s.x.LegacyDrawing = sml.NewCT_LegacyDrawing()
|
||||
}
|
||||
|
@ -90,8 +90,9 @@ func (wb *Workbook) AddSheet() Sheet {
|
||||
wb.comments = append(wb.comments, nil)
|
||||
|
||||
dt := gooxml.DocTypeSpreadsheet
|
||||
|
||||
// update the references
|
||||
rid := wb.wbRels.AddAutoRelationship(dt, len(wb.x.Sheets.Sheet), gooxml.WorksheetType)
|
||||
rid := wb.wbRels.AddAutoRelationship(dt, gooxml.OfficeDocumentType, len(wb.x.Sheets.Sheet), gooxml.WorksheetType)
|
||||
rs.IdAttr = rid.ID()
|
||||
|
||||
// add the content type
|
||||
@ -308,28 +309,28 @@ func (wb *Workbook) onNewRelationship(decMap *zippkg.DecodeMap, target, typ stri
|
||||
switch typ {
|
||||
case gooxml.OfficeDocumentType:
|
||||
wb.x = sml.NewWorkbook()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: wb.x})
|
||||
decMap.AddTarget(target, wb.x, typ, 0)
|
||||
// look for the workbook relationships file as well
|
||||
wb.wbRels = common.NewRelationships()
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(target), Ifc: wb.wbRels.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(target), wb.wbRels.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.CorePropertiesType:
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: wb.CoreProperties.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, wb.CoreProperties.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.ExtendedPropertiesType:
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: wb.AppProperties.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, wb.AppProperties.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.WorksheetType:
|
||||
ws := sml.NewWorksheet()
|
||||
idx := uint32(len(wb.xws))
|
||||
wb.xws = append(wb.xws, ws)
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: ws, Index: idx})
|
||||
decMap.AddTarget(target, ws, typ, idx)
|
||||
// look for worksheet rels
|
||||
wksRel := common.NewRelationships()
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(target), Ifc: wksRel.X(), Index: idx})
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(target), wksRel.X(), typ, 0)
|
||||
wb.xwsRels = append(wb.xwsRels, wksRel)
|
||||
|
||||
// add a comments placeholder that will be replaced if we see a comments
|
||||
@ -338,23 +339,23 @@ func (wb *Workbook) onNewRelationship(decMap *zippkg.DecodeMap, target, typ stri
|
||||
|
||||
// fix the relationship target so it points to where we'll save
|
||||
// the worksheet
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.xws))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.xws))
|
||||
|
||||
case gooxml.StylesType:
|
||||
wb.StyleSheet = NewStyleSheet(wb)
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: wb.StyleSheet.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, wb.StyleSheet.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.ThemeType:
|
||||
thm := dml.NewTheme()
|
||||
wb.themes = append(wb.themes, thm)
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: thm})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.themes))
|
||||
decMap.AddTarget(target, thm, typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.themes))
|
||||
|
||||
case gooxml.SharedStingsType:
|
||||
wb.SharedStrings = NewSharedStrings()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: wb.SharedStrings.X()})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, 0)
|
||||
decMap.AddTarget(target, wb.SharedStrings.X(), typ, 0)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, 0)
|
||||
|
||||
case gooxml.ThumbnailType:
|
||||
// read our thumbnail
|
||||
@ -399,73 +400,73 @@ func (wb *Workbook) onNewRelationship(decMap *zippkg.DecodeMap, target, typ stri
|
||||
case gooxml.DrawingType:
|
||||
drawing := sd.NewWsDr()
|
||||
idx := uint32(len(wb.drawings))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: drawing, Index: idx})
|
||||
decMap.AddTarget(target, drawing, typ, idx)
|
||||
wb.drawings = append(wb.drawings, drawing)
|
||||
|
||||
drel := common.NewRelationships()
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(target), Ifc: drel.X(), Index: idx})
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(target), drel.X(), typ, idx)
|
||||
wb.drawingRels = append(wb.drawingRels, drel)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.drawings))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.drawings))
|
||||
|
||||
case gooxml.VMLDrawingType:
|
||||
vd := vmldrawing.NewContainer()
|
||||
idx := uint32(len(wb.vmlDrawings))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: vd, Index: idx})
|
||||
decMap.AddTarget(target, vd, typ, idx)
|
||||
wb.vmlDrawings = append(wb.vmlDrawings, vd)
|
||||
|
||||
case gooxml.CommentsType:
|
||||
wb.comments[src.Index] = sml.NewComments()
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: wb.comments[src.Index], Index: src.Index})
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.comments))
|
||||
decMap.AddTarget(target, wb.comments[src.Index], typ, src.Index)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.comments))
|
||||
|
||||
case gooxml.ChartType:
|
||||
chart := crt.NewChartSpace()
|
||||
idx := uint32(len(wb.charts))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: chart, Index: idx})
|
||||
decMap.AddTarget(target, chart, typ, idx)
|
||||
wb.charts = append(wb.charts, chart)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.charts))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.charts))
|
||||
|
||||
case gooxml.TableType:
|
||||
tbl := sml.NewTable()
|
||||
idx := uint32(len(wb.tables))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: tbl, Index: idx})
|
||||
decMap.AddTarget(target, tbl, typ, idx)
|
||||
wb.tables = append(wb.tables, tbl)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.tables))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.tables))
|
||||
|
||||
case gooxml.PivotTableType:
|
||||
tbl := sml.NewPivotTableDefinition()
|
||||
idx := uint32(len(wb.pivotTables))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: tbl, Index: idx})
|
||||
decMap.AddTarget(target, tbl, typ, idx)
|
||||
wb.pivotTables = append(wb.pivotTables, tbl)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.pivotTables))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.pivotTables))
|
||||
|
||||
fn := gooxml.AbsoluteFilename(dt, typ, len(wb.pivotTables))
|
||||
tblRel := common.NewRelationships()
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(fn), Ifc: tblRel.X(), Index: idx})
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(fn), tblRel.X(), typ, idx)
|
||||
wb.pivotTableRels = append(wb.pivotTableRels, tblRel)
|
||||
|
||||
case gooxml.PivotCacheDefinitionType:
|
||||
cd := sml.NewPivotCacheDefinition()
|
||||
idx := uint32(len(wb.pivotCache))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: cd, Index: idx})
|
||||
decMap.AddTarget(target, cd, typ, idx)
|
||||
wb.pivotCache = append(wb.pivotCache, cd)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.pivotCache))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.pivotCache))
|
||||
|
||||
fn := gooxml.AbsoluteFilename(dt, typ, len(wb.pivotCache))
|
||||
cdRel := common.NewRelationships()
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(fn), Ifc: cdRel.X(), Index: idx})
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(fn), cdRel.X(), typ, idx)
|
||||
wb.pivotCacheRels = append(wb.pivotCacheRels, cdRel)
|
||||
|
||||
case gooxml.PivotCacheRecordsType:
|
||||
cd := sml.NewPivotCacheRecords()
|
||||
idx := uint32(len(wb.pivotRecords))
|
||||
decMap.AddTarget(zippkg.Target{Path: target, Ifc: cd, Index: idx})
|
||||
decMap.AddTarget(target, cd, typ, idx)
|
||||
wb.pivotRecords = append(wb.pivotRecords, cd)
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, typ, len(wb.pivotRecords))
|
||||
rel.TargetAttr = gooxml.RelativeFilename(dt, src.Typ, typ, len(wb.pivotRecords))
|
||||
|
||||
fn := gooxml.AbsoluteFilename(dt, typ, len(wb.pivotRecords))
|
||||
cdRel := common.NewRelationships()
|
||||
decMap.AddTarget(zippkg.Target{Path: zippkg.RelationsPathFor(fn), Ifc: cdRel.X(), Index: idx})
|
||||
decMap.AddTarget(zippkg.RelationsPathFor(fn), cdRel.X(), typ, idx)
|
||||
wb.pivotRecordRels = append(wb.pivotRecordRels, cdRel)
|
||||
|
||||
default:
|
||||
@ -615,3 +616,12 @@ func (wb *Workbook) Protection() WorkbookProtection {
|
||||
}
|
||||
return WorkbookProtection{wb.x.WorkbookProtection}
|
||||
}
|
||||
|
||||
func (wb *Workbook) GetSheet(name string) Sheet {
|
||||
for _, s := range wb.Sheets() {
|
||||
if s.Name() == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return Sheet{}
|
||||
}
|
||||
|
@ -45,19 +45,22 @@ func (d *DecodeMap) SetOnNewRelationshipFunc(fn OnNewRelationshipFunc) {
|
||||
|
||||
type Target struct {
|
||||
Path string
|
||||
Typ string
|
||||
Ifc interface{}
|
||||
Index uint32
|
||||
}
|
||||
|
||||
// AddTarget allows documents to register decode targets. Path is a path that
|
||||
// will be found in the zip file and ifc is an XML element that the file will be
|
||||
// unmarshaled to.
|
||||
func (d *DecodeMap) AddTarget(tgt Target) {
|
||||
// unmarshaled to. filePath is the absolute path to the target, ifc is the
|
||||
// object to decode into, sourceFileType is the type of file that the reference
|
||||
// was discovered in, and index is the index of the source file type.
|
||||
func (d *DecodeMap) AddTarget(filePath string, ifc interface{}, sourceFileType string, idx uint32) {
|
||||
if d.pathsToIfcs == nil {
|
||||
d.pathsToIfcs = make(map[string]Target)
|
||||
d.basePaths = make(map[*relationships.Relationships]string)
|
||||
}
|
||||
d.pathsToIfcs[filepath.Clean(tgt.Path)] = tgt
|
||||
d.pathsToIfcs[filepath.Clean(filePath)] = Target{Path: filePath, Typ: sourceFileType, Ifc: ifc, Index: idx}
|
||||
}
|
||||
|
||||
// Decode loops decoding targets registered with AddTarget and calling th
|
||||
|
Loading…
x
Reference in New Issue
Block a user