@@ -98,6 +98,11 @@ struct InnerCell {
98
98
style : Option < u32 >
99
99
}
100
100
101
+ #[ derive( Clone ) ]
102
+ struct Hyperlink {
103
+ cell : String ,
104
+ url : String ,
105
+ }
101
106
impl InnerCell {
102
107
pub fn new ( cell : String , style : & Option < u32 > ) -> InnerCell {
103
108
InnerCell {
@@ -132,9 +137,9 @@ pub fn import_to_xlsx(raw_data: &JsValue) -> Vec<u8> {
132
137
let w = Cursor :: new ( buf) ;
133
138
let mut zip = zip:: ZipWriter :: new ( w) ;
134
139
let options = FileOptions :: default ( ) . compression_method ( zip:: CompressionMethod :: Stored ) . unix_permissions ( 0o755 ) ;
135
-
136
140
for ( sheet_index, sheet) in data. data . iter ( ) . enumerate ( ) {
137
141
let mut rows: Vec < Vec < InnerCell > > = vec ! ( ) ;
142
+ let mut hyperlinks: Vec < Hyperlink > = vec ! [ ] ;
138
143
match & sheet. cells {
139
144
Some ( cells) => {
140
145
for ( row_index, row) in cells. iter ( ) . enumerate ( ) {
@@ -144,7 +149,12 @@ pub fn import_to_xlsx(raw_data: &JsValue) -> Vec<u8> {
144
149
Some ( cell) => {
145
150
let cell_name = cell_offsets_to_index ( row_index, col_index) ;
146
151
let mut inner_cell = InnerCell :: new ( cell_name, & cell. s ) ;
147
-
152
+ if let Some ( link) = & cell. hyperlink {
153
+ hyperlinks. push ( Hyperlink {
154
+ cell : inner_cell. cell . clone ( ) ,
155
+ url : link. clone ( ) ,
156
+ } ) ;
157
+ }
148
158
match & cell. v {
149
159
Some ( value) => {
150
160
if !value. is_empty ( ) {
@@ -222,6 +232,9 @@ pub fn import_to_xlsx(raw_data: &JsValue) -> Vec<u8> {
222
232
}
223
233
224
234
let sheet_info = get_sheet_info ( sheet. name . clone ( ) , sheet_index) ;
235
+ let rels_path = format ! ( "xl/worksheets/_rels/sheet{}.xml.rels" , sheet_index + 1 ) ;
236
+ zip. start_file ( rels_path. clone ( ) , options) . unwrap ( ) ;
237
+ zip. write_all ( get_sheet_rels ( & hyperlinks) . as_bytes ( ) ) . unwrap ( ) ;
225
238
zip. start_file ( sheet_info. 0 . clone ( ) , options) . unwrap ( ) ;
226
239
zip. write_all (
227
240
get_sheet_data (
@@ -232,6 +245,7 @@ pub fn import_to_xlsx(raw_data: &JsValue) -> Vec<u8> {
232
245
sheet. frozen_rows ,
233
246
sheet. frozen_cols ,
234
247
& sheet. validations ,
248
+ & hyperlinks,
235
249
)
236
250
. as_bytes ( ) ,
237
251
) . unwrap ( ) ;
@@ -448,6 +462,7 @@ fn get_sheet_data(
448
462
frozen_rows : Option < u32 > ,
449
463
frozen_cols : Option < u32 > ,
450
464
validations : & Option < Vec < DataValidation > > ,
465
+ hyperlinks : & [ Hyperlink ] ,
451
466
) -> String {
452
467
let mut worksheet = Element :: new ( "worksheet" ) ;
453
468
let mut sheet_view = Element :: new ( "sheetView" ) ;
@@ -651,6 +666,22 @@ fn get_sheet_data(
651
666
worksheet_children. push ( dv_el) ;
652
667
}
653
668
}
669
+ if !hyperlinks. is_empty ( ) {
670
+ let mut hyperlinks_el = Element :: new ( "hyperlinks" ) ;
671
+ let mut hyperlink_children = vec ! [ ] ;
672
+
673
+ for ( i, h) in hyperlinks. iter ( ) . enumerate ( ) {
674
+ let mut hyperlink_el = Element :: new ( "hyperlink" ) ;
675
+ hyperlink_el
676
+ . add_attr ( "r:id" , format ! ( "rId{}" , 1000 + i) )
677
+ . add_attr ( "ref" , & h. cell ) ;
678
+ hyperlink_children. push ( hyperlink_el) ;
679
+ }
680
+
681
+ hyperlinks_el. add_children ( hyperlink_children) ;
682
+ worksheet_children. push ( hyperlinks_el) ;
683
+ }
684
+
654
685
worksheet
655
686
. add_attr ( "xmlns:xm" , "http://schemas.microsoft.com/office/excel/2006/main" )
656
687
. add_attr ( "xmlns:x14ac" , "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" )
@@ -689,6 +720,25 @@ fn get_sheet_info(name: Option<String>, index: usize) -> (String, String) {
689
720
( format ! ( "xl/worksheets/sheet{}.xml" , index + 1 ) , sheet_name)
690
721
}
691
722
723
+ fn get_sheet_rels ( hyperlinks : & [ Hyperlink ] ) -> String {
724
+ let mut rels = Element :: new ( "Relationships" ) ;
725
+ rels. add_attr ( "xmlns" , "http://schemas.openxmlformats.org/package/2006/relationships" ) ;
726
+
727
+ let mut children = vec ! [ ] ;
728
+
729
+ for ( i, link) in hyperlinks. iter ( ) . enumerate ( ) {
730
+ let mut rel = Element :: new ( "Relationship" ) ;
731
+ rel. add_attr ( "Id" , format ! ( "rId{}" , 1000 + i) ) ;
732
+ rel. add_attr ( "Type" , "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ) ;
733
+ rel. add_attr ( "Target" , & link. url ) ;
734
+ rel. add_attr ( "TargetMode" , "External" ) ;
735
+ children. push ( rel) ;
736
+ }
737
+
738
+ rels. add_children ( children) ;
739
+ rels. to_xml ( )
740
+ }
741
+
692
742
fn get_nav ( sheets : Vec < ( String , String ) > ) -> ( String , String , String ) {
693
743
let mut content_types = Element :: new ( "Types" ) ;
694
744
content_types. add_attr ( "xmlns" , "http://schemas.openxmlformats.org/package/2006/content-types" ) ;
0 commit comments