diff --git a/file_test.go b/file_test.go index 71797185..06e03097 100644 --- a/file_test.go +++ b/file_test.go @@ -907,6 +907,14 @@ func TestFile(t *testing.T) { c.Assert(cell1.Value, qt.Equals, "A cell!") }) + csRunO(c, "OpenAndMarshalFileWithHyperlinks", func(c *qt.C, option FileOption) { + f, err := OpenFile("./testdocs/file_with_hyperlinks.xlsx", option) + c.Assert(err, qt.IsNil) + parts, err := f.MakeStreamParts() + c.Assert(err, qt.IsNil) + c.Assert(parts["xl/worksheets/_rels/sheet1.xml.rels"], qt.Contains, `Target="https://www.google.com/" TargetMode="External"`) + }) + csRunO(c, "TestMarshalFileWithHyperlinks", func(c *qt.C, option FileOption) { f := NewFile(option) sheet1, _ := f.AddSheet("MySheet") diff --git a/lib.go b/lib.go index 7e40a0e1..0223d9cd 100644 --- a/lib.go +++ b/lib.go @@ -637,9 +637,34 @@ type coord struct { y int } +func makeRelations(fi *File, rsheet *xlsxSheet) (*xlsxRels, error) { + rels := new(xlsxRels) + + wrap := func(err error) (*xlsxRels, error) { + return nil, fmt.Errorf("makeRelations: %w", err) + } + + relsFile, ok := fi.worksheetRels["sheet"+rsheet.SheetId] + if ok { + rc, err := relsFile.Open() + if err != nil { + return wrap(fmt.Errorf("file.Open: %w", err)) + } + defer rc.Close() + + decoder := xml.NewDecoder(rc) + err = decoder.Decode(rels) + if err != nil { + return wrap(fmt.Errorf("xml.Decoder.Decode: %w", err)) + } + } + + return rels, nil +} + type hyperlinkTable map[coord]Hyperlink -func makeHyperlinkTable(worksheet *xlsxWorksheet, fi *File, rsheet *xlsxSheet) (hyperlinkTable, error) { +func makeHyperlinkTable(worksheet *xlsxWorksheet, rels *xlsxRels) (hyperlinkTable, error) { wrap := func(err error) (hyperlinkTable, error) { return nil, fmt.Errorf("makeHyperlinkTable: %w", err) } @@ -648,26 +673,10 @@ func makeHyperlinkTable(worksheet *xlsxWorksheet, fi *File, rsheet *xlsxSheet) ( // Convert xlsxHyperlinks to Hyperlinks if worksheet.Hyperlinks != nil { - - worksheetRelsFile, ok := fi.worksheetRels["sheet"+rsheet.SheetId] - worksheetRels := new(xlsxWorksheetRels) - if ok { - rc, err := worksheetRelsFile.Open() - if err != nil { - return wrap(fmt.Errorf("file.Open: %w", err)) - } - defer rc.Close() - - decoder := xml.NewDecoder(rc) - err = decoder.Decode(worksheetRels) - if err != nil { - return wrap(fmt.Errorf("xml.Decoder.Decode: %w", err)) - } - } for _, xlsxLink := range worksheet.Hyperlinks.HyperLinks { newHyperLink := Hyperlink{} - for _, rel := range worksheetRels.Relationships { + for _, rel := range rels.Relationships { if rel.Id == xlsxLink.RelationshipId { newHyperLink.Link = rel.Target break @@ -724,12 +733,24 @@ func readSheetFromFile(rsheet xlsxSheet, fi *File, sheetXMLMap map[string]string return wrap(err) } - linkTable, err := makeHyperlinkTable(worksheet, fi, &rsheet) + sheet, err = NewSheetWithCellStore(rsheet.Name, fi.cellStoreConstructor) if err != nil { return wrap(err) } - sheet, err = NewSheetWithCellStore(rsheet.Name, fi.cellStoreConstructor) + rels, err := makeRelations(fi, &rsheet) + if err != nil { + return wrap(err) + } + for _, rel := range rels.Relationships { + sheet.Relations = append(sheet.Relations, Relation{ + Type: rel.Type, + Target: rel.Target, + TargetMode: rel.TargetMode, + }) + } + + linkTable, err := makeHyperlinkTable(worksheet, rels) if err != nil { return wrap(err) } diff --git a/xlsxRelation.go b/xlsxRelation.go new file mode 100644 index 00000000..d79319e8 --- /dev/null +++ b/xlsxRelation.go @@ -0,0 +1,27 @@ +package xlsx + +import "encoding/xml" + +type RelationshipType string + +const ( + RelationshipTypeHyperlink RelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" +) + +type RelationshipTargetMode string + +const ( + RelationshipTargetModeExternal RelationshipTargetMode = "External" +) + +type xlsxRels struct { + XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"` + Relationships []xlsxRelation `xml:"Relationship"` +} + +type xlsxRelation struct { + Id string `xml:"Id,attr"` + Type RelationshipType `xml:"Type,attr"` + Target string `xml:"Target,attr"` + TargetMode RelationshipTargetMode `xml:"TargetMode,attr,omitempty"` +} diff --git a/xmlWorksheet.go b/xmlWorksheet.go index 1b1d6195..9a379ad1 100644 --- a/xmlWorksheet.go +++ b/xmlWorksheet.go @@ -11,18 +11,6 @@ import ( "github.com/shabbyrobe/xmlwriter" ) -type RelationshipType string - -const ( - RelationshipTypeHyperlink RelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" -) - -type RelationshipTargetMode string - -const ( - RelationshipTargetModeExternal RelationshipTargetMode = "External" -) - // xlsxWorksheetRels contains xlsxWorksheetRelation type xlsxWorksheetRels struct { XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`