split out filename work

This commit is contained in:
Todd 2017-09-28 17:05:38 -05:00
parent 67d22cab80
commit 771c550c7f
11 changed files with 177 additions and 204 deletions

13
algo/strings.go Normal file
View 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)
}

View File

@ -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.

View File

@ -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 {

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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{}
}

View File

@ -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