1use serde::{Deserialize, Serialize};
6
7use crate::namespaces;
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11#[serde(rename = "worksheet")]
12pub struct WorksheetXml {
13 #[serde(rename = "@xmlns")]
14 pub xmlns: String,
15
16 #[serde(rename = "@xmlns:r")]
17 pub xmlns_r: String,
18
19 #[serde(rename = "sheetPr", skip_serializing_if = "Option::is_none")]
20 pub sheet_pr: Option<SheetPr>,
21
22 #[serde(rename = "dimension", skip_serializing_if = "Option::is_none")]
23 pub dimension: Option<Dimension>,
24
25 #[serde(rename = "sheetViews", skip_serializing_if = "Option::is_none")]
26 pub sheet_views: Option<SheetViews>,
27
28 #[serde(rename = "sheetFormatPr", skip_serializing_if = "Option::is_none")]
29 pub sheet_format_pr: Option<SheetFormatPr>,
30
31 #[serde(rename = "cols", skip_serializing_if = "Option::is_none")]
32 pub cols: Option<Cols>,
33
34 #[serde(rename = "sheetData")]
35 pub sheet_data: SheetData,
36
37 #[serde(rename = "sheetProtection", skip_serializing_if = "Option::is_none")]
38 pub sheet_protection: Option<SheetProtection>,
39
40 #[serde(rename = "autoFilter", skip_serializing_if = "Option::is_none")]
41 pub auto_filter: Option<AutoFilter>,
42
43 #[serde(rename = "mergeCells", skip_serializing_if = "Option::is_none")]
44 pub merge_cells: Option<MergeCells>,
45
46 #[serde(
47 rename = "conditionalFormatting",
48 default,
49 skip_serializing_if = "Vec::is_empty"
50 )]
51 pub conditional_formatting: Vec<ConditionalFormatting>,
52
53 #[serde(rename = "dataValidations", skip_serializing_if = "Option::is_none")]
54 pub data_validations: Option<DataValidations>,
55
56 #[serde(rename = "hyperlinks", skip_serializing_if = "Option::is_none")]
57 pub hyperlinks: Option<Hyperlinks>,
58
59 #[serde(rename = "printOptions", skip_serializing_if = "Option::is_none")]
60 pub print_options: Option<PrintOptions>,
61
62 #[serde(rename = "pageMargins", skip_serializing_if = "Option::is_none")]
63 pub page_margins: Option<PageMargins>,
64
65 #[serde(rename = "pageSetup", skip_serializing_if = "Option::is_none")]
66 pub page_setup: Option<PageSetup>,
67
68 #[serde(rename = "headerFooter", skip_serializing_if = "Option::is_none")]
69 pub header_footer: Option<HeaderFooter>,
70
71 #[serde(rename = "rowBreaks", skip_serializing_if = "Option::is_none")]
72 pub row_breaks: Option<RowBreaks>,
73
74 #[serde(rename = "drawing", skip_serializing_if = "Option::is_none")]
75 pub drawing: Option<DrawingRef>,
76
77 #[serde(rename = "legacyDrawing", skip_serializing_if = "Option::is_none")]
78 pub legacy_drawing: Option<LegacyDrawingRef>,
79
80 #[serde(rename = "tableParts", skip_serializing_if = "Option::is_none")]
81 pub table_parts: Option<TableParts>,
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86pub struct Dimension {
87 #[serde(rename = "@ref")]
88 pub reference: String,
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct SheetViews {
94 #[serde(rename = "sheetView")]
95 pub sheet_views: Vec<SheetView>,
96}
97
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
100pub struct SheetView {
101 #[serde(rename = "@tabSelected", skip_serializing_if = "Option::is_none")]
102 pub tab_selected: Option<bool>,
103
104 #[serde(rename = "@zoomScale", skip_serializing_if = "Option::is_none")]
105 pub zoom_scale: Option<u32>,
106
107 #[serde(rename = "@workbookViewId")]
108 pub workbook_view_id: u32,
109
110 #[serde(rename = "pane", skip_serializing_if = "Option::is_none")]
111 pub pane: Option<Pane>,
112
113 #[serde(rename = "selection", default)]
114 pub selection: Vec<Selection>,
115}
116
117#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct Pane {
120 #[serde(rename = "@xSplit", skip_serializing_if = "Option::is_none")]
121 pub x_split: Option<u32>,
122
123 #[serde(rename = "@ySplit", skip_serializing_if = "Option::is_none")]
124 pub y_split: Option<u32>,
125
126 #[serde(rename = "@topLeftCell", skip_serializing_if = "Option::is_none")]
127 pub top_left_cell: Option<String>,
128
129 #[serde(rename = "@activePane", skip_serializing_if = "Option::is_none")]
130 pub active_pane: Option<String>,
131
132 #[serde(rename = "@state", skip_serializing_if = "Option::is_none")]
133 pub state: Option<String>,
134}
135
136#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
138pub struct Selection {
139 #[serde(rename = "@pane", skip_serializing_if = "Option::is_none")]
140 pub pane: Option<String>,
141
142 #[serde(rename = "@activeCell", skip_serializing_if = "Option::is_none")]
143 pub active_cell: Option<String>,
144
145 #[serde(rename = "@sqref", skip_serializing_if = "Option::is_none")]
146 pub sqref: Option<String>,
147}
148
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
151pub struct SheetPr {
152 #[serde(rename = "@codeName", skip_serializing_if = "Option::is_none")]
153 pub code_name: Option<String>,
154
155 #[serde(rename = "@filterMode", skip_serializing_if = "Option::is_none")]
156 pub filter_mode: Option<bool>,
157
158 #[serde(rename = "tabColor", skip_serializing_if = "Option::is_none")]
159 pub tab_color: Option<TabColor>,
160
161 #[serde(rename = "outlinePr", skip_serializing_if = "Option::is_none")]
162 pub outline_pr: Option<OutlinePr>,
163}
164
165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
167pub struct TabColor {
168 #[serde(rename = "@rgb", skip_serializing_if = "Option::is_none")]
169 pub rgb: Option<String>,
170
171 #[serde(rename = "@theme", skip_serializing_if = "Option::is_none")]
172 pub theme: Option<u32>,
173
174 #[serde(rename = "@indexed", skip_serializing_if = "Option::is_none")]
175 pub indexed: Option<u32>,
176}
177
178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
180pub struct OutlinePr {
181 #[serde(rename = "@summaryBelow", skip_serializing_if = "Option::is_none")]
182 pub summary_below: Option<bool>,
183
184 #[serde(rename = "@summaryRight", skip_serializing_if = "Option::is_none")]
185 pub summary_right: Option<bool>,
186}
187
188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub struct SheetFormatPr {
191 #[serde(rename = "@defaultRowHeight")]
192 pub default_row_height: f64,
193
194 #[serde(rename = "@defaultColWidth", skip_serializing_if = "Option::is_none")]
195 pub default_col_width: Option<f64>,
196
197 #[serde(rename = "@customHeight", skip_serializing_if = "Option::is_none")]
198 pub custom_height: Option<bool>,
199
200 #[serde(rename = "@outlineLevelRow", skip_serializing_if = "Option::is_none")]
201 pub outline_level_row: Option<u8>,
202
203 #[serde(rename = "@outlineLevelCol", skip_serializing_if = "Option::is_none")]
204 pub outline_level_col: Option<u8>,
205}
206
207#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
209pub struct SheetProtection {
210 #[serde(rename = "@password", skip_serializing_if = "Option::is_none")]
211 pub password: Option<String>,
212
213 #[serde(rename = "@sheet", skip_serializing_if = "Option::is_none")]
214 pub sheet: Option<bool>,
215
216 #[serde(rename = "@objects", skip_serializing_if = "Option::is_none")]
217 pub objects: Option<bool>,
218
219 #[serde(rename = "@scenarios", skip_serializing_if = "Option::is_none")]
220 pub scenarios: Option<bool>,
221
222 #[serde(rename = "@selectLockedCells", skip_serializing_if = "Option::is_none")]
223 pub select_locked_cells: Option<bool>,
224
225 #[serde(
226 rename = "@selectUnlockedCells",
227 skip_serializing_if = "Option::is_none"
228 )]
229 pub select_unlocked_cells: Option<bool>,
230
231 #[serde(rename = "@formatCells", skip_serializing_if = "Option::is_none")]
232 pub format_cells: Option<bool>,
233
234 #[serde(rename = "@formatColumns", skip_serializing_if = "Option::is_none")]
235 pub format_columns: Option<bool>,
236
237 #[serde(rename = "@formatRows", skip_serializing_if = "Option::is_none")]
238 pub format_rows: Option<bool>,
239
240 #[serde(rename = "@insertColumns", skip_serializing_if = "Option::is_none")]
241 pub insert_columns: Option<bool>,
242
243 #[serde(rename = "@insertRows", skip_serializing_if = "Option::is_none")]
244 pub insert_rows: Option<bool>,
245
246 #[serde(rename = "@insertHyperlinks", skip_serializing_if = "Option::is_none")]
247 pub insert_hyperlinks: Option<bool>,
248
249 #[serde(rename = "@deleteColumns", skip_serializing_if = "Option::is_none")]
250 pub delete_columns: Option<bool>,
251
252 #[serde(rename = "@deleteRows", skip_serializing_if = "Option::is_none")]
253 pub delete_rows: Option<bool>,
254
255 #[serde(rename = "@sort", skip_serializing_if = "Option::is_none")]
256 pub sort: Option<bool>,
257
258 #[serde(rename = "@autoFilter", skip_serializing_if = "Option::is_none")]
259 pub auto_filter: Option<bool>,
260
261 #[serde(rename = "@pivotTables", skip_serializing_if = "Option::is_none")]
262 pub pivot_tables: Option<bool>,
263}
264
265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
267pub struct Cols {
268 #[serde(rename = "col")]
269 pub cols: Vec<Col>,
270}
271
272#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
274pub struct Col {
275 #[serde(rename = "@min")]
276 pub min: u32,
277
278 #[serde(rename = "@max")]
279 pub max: u32,
280
281 #[serde(rename = "@width", skip_serializing_if = "Option::is_none")]
282 pub width: Option<f64>,
283
284 #[serde(rename = "@style", skip_serializing_if = "Option::is_none")]
285 pub style: Option<u32>,
286
287 #[serde(rename = "@hidden", skip_serializing_if = "Option::is_none")]
288 pub hidden: Option<bool>,
289
290 #[serde(rename = "@customWidth", skip_serializing_if = "Option::is_none")]
291 pub custom_width: Option<bool>,
292
293 #[serde(rename = "@outlineLevel", skip_serializing_if = "Option::is_none")]
294 pub outline_level: Option<u8>,
295}
296
297#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
299pub struct SheetData {
300 #[serde(rename = "row", default)]
301 pub rows: Vec<Row>,
302}
303
304#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
306pub struct Row {
307 #[serde(rename = "@r")]
309 pub r: u32,
310
311 #[serde(rename = "@spans", skip_serializing_if = "Option::is_none")]
312 pub spans: Option<String>,
313
314 #[serde(rename = "@s", skip_serializing_if = "Option::is_none")]
315 pub s: Option<u32>,
316
317 #[serde(rename = "@customFormat", skip_serializing_if = "Option::is_none")]
318 pub custom_format: Option<bool>,
319
320 #[serde(rename = "@ht", skip_serializing_if = "Option::is_none")]
321 pub ht: Option<f64>,
322
323 #[serde(rename = "@hidden", skip_serializing_if = "Option::is_none")]
324 pub hidden: Option<bool>,
325
326 #[serde(rename = "@customHeight", skip_serializing_if = "Option::is_none")]
327 pub custom_height: Option<bool>,
328
329 #[serde(rename = "@outlineLevel", skip_serializing_if = "Option::is_none")]
330 pub outline_level: Option<u8>,
331
332 #[serde(rename = "c", default)]
333 pub cells: Vec<Cell>,
334}
335
336#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
338pub struct Cell {
339 #[serde(rename = "@r")]
341 pub r: String,
342
343 #[serde(rename = "@s", skip_serializing_if = "Option::is_none")]
345 pub s: Option<u32>,
346
347 #[serde(rename = "@t", skip_serializing_if = "Option::is_none")]
349 pub t: Option<String>,
350
351 #[serde(rename = "v", skip_serializing_if = "Option::is_none")]
353 pub v: Option<String>,
354
355 #[serde(rename = "f", skip_serializing_if = "Option::is_none")]
357 pub f: Option<CellFormula>,
358
359 #[serde(rename = "is", skip_serializing_if = "Option::is_none")]
361 pub is: Option<InlineString>,
362}
363
364pub mod cell_types {
366 pub const BOOLEAN: &str = "b";
367 pub const DATE: &str = "d";
368 pub const ERROR: &str = "e";
369 pub const INLINE_STRING: &str = "inlineStr";
370 pub const NUMBER: &str = "n";
371 pub const SHARED_STRING: &str = "s";
372 pub const FORMULA_STRING: &str = "str";
373}
374
375#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
377pub struct CellFormula {
378 #[serde(rename = "@t", skip_serializing_if = "Option::is_none")]
379 pub t: Option<String>,
380
381 #[serde(rename = "@ref", skip_serializing_if = "Option::is_none")]
382 pub reference: Option<String>,
383
384 #[serde(rename = "@si", skip_serializing_if = "Option::is_none")]
385 pub si: Option<u32>,
386
387 #[serde(rename = "$value", skip_serializing_if = "Option::is_none")]
388 pub value: Option<String>,
389}
390
391#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
393pub struct InlineString {
394 #[serde(rename = "t", skip_serializing_if = "Option::is_none")]
395 pub t: Option<String>,
396}
397
398#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
400pub struct AutoFilter {
401 #[serde(rename = "@ref")]
402 pub reference: String,
403}
404
405#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
407pub struct DataValidations {
408 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
409 pub count: Option<u32>,
410
411 #[serde(rename = "dataValidation", default)]
412 pub data_validations: Vec<DataValidation>,
413}
414
415#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
417pub struct DataValidation {
418 #[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
419 pub validation_type: Option<String>,
420
421 #[serde(rename = "@operator", skip_serializing_if = "Option::is_none")]
422 pub operator: Option<String>,
423
424 #[serde(rename = "@allowBlank", skip_serializing_if = "Option::is_none")]
425 pub allow_blank: Option<bool>,
426
427 #[serde(rename = "@showInputMessage", skip_serializing_if = "Option::is_none")]
428 pub show_input_message: Option<bool>,
429
430 #[serde(rename = "@showErrorMessage", skip_serializing_if = "Option::is_none")]
431 pub show_error_message: Option<bool>,
432
433 #[serde(rename = "@errorStyle", skip_serializing_if = "Option::is_none")]
434 pub error_style: Option<String>,
435
436 #[serde(rename = "@errorTitle", skip_serializing_if = "Option::is_none")]
437 pub error_title: Option<String>,
438
439 #[serde(rename = "@error", skip_serializing_if = "Option::is_none")]
440 pub error: Option<String>,
441
442 #[serde(rename = "@promptTitle", skip_serializing_if = "Option::is_none")]
443 pub prompt_title: Option<String>,
444
445 #[serde(rename = "@prompt", skip_serializing_if = "Option::is_none")]
446 pub prompt: Option<String>,
447
448 #[serde(rename = "@sqref")]
449 pub sqref: String,
450
451 #[serde(rename = "formula1", skip_serializing_if = "Option::is_none")]
452 pub formula1: Option<String>,
453
454 #[serde(rename = "formula2", skip_serializing_if = "Option::is_none")]
455 pub formula2: Option<String>,
456}
457
458#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
460pub struct MergeCells {
461 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
462 pub count: Option<u32>,
463
464 #[serde(rename = "mergeCell", default)]
465 pub merge_cells: Vec<MergeCell>,
466}
467
468#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
470pub struct MergeCell {
471 #[serde(rename = "@ref")]
472 pub reference: String,
473}
474
475#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
477pub struct Hyperlinks {
478 #[serde(rename = "hyperlink", default)]
479 pub hyperlinks: Vec<Hyperlink>,
480}
481
482#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484pub struct Hyperlink {
485 #[serde(rename = "@ref")]
486 pub reference: String,
487
488 #[serde(
489 rename = "@r:id",
490 alias = "@id",
491 skip_serializing_if = "Option::is_none"
492 )]
493 pub r_id: Option<String>,
494
495 #[serde(rename = "@location", skip_serializing_if = "Option::is_none")]
496 pub location: Option<String>,
497
498 #[serde(rename = "@display", skip_serializing_if = "Option::is_none")]
499 pub display: Option<String>,
500
501 #[serde(rename = "@tooltip", skip_serializing_if = "Option::is_none")]
502 pub tooltip: Option<String>,
503}
504
505#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
507pub struct PageMargins {
508 #[serde(rename = "@left")]
509 pub left: f64,
510
511 #[serde(rename = "@right")]
512 pub right: f64,
513
514 #[serde(rename = "@top")]
515 pub top: f64,
516
517 #[serde(rename = "@bottom")]
518 pub bottom: f64,
519
520 #[serde(rename = "@header")]
521 pub header: f64,
522
523 #[serde(rename = "@footer")]
524 pub footer: f64,
525}
526
527#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
529pub struct PageSetup {
530 #[serde(rename = "@paperSize", skip_serializing_if = "Option::is_none")]
531 pub paper_size: Option<u32>,
532
533 #[serde(rename = "@orientation", skip_serializing_if = "Option::is_none")]
534 pub orientation: Option<String>,
535
536 #[serde(rename = "@scale", skip_serializing_if = "Option::is_none")]
537 pub scale: Option<u32>,
538
539 #[serde(rename = "@fitToWidth", skip_serializing_if = "Option::is_none")]
540 pub fit_to_width: Option<u32>,
541
542 #[serde(rename = "@fitToHeight", skip_serializing_if = "Option::is_none")]
543 pub fit_to_height: Option<u32>,
544
545 #[serde(rename = "@firstPageNumber", skip_serializing_if = "Option::is_none")]
546 pub first_page_number: Option<u32>,
547
548 #[serde(rename = "@horizontalDpi", skip_serializing_if = "Option::is_none")]
549 pub horizontal_dpi: Option<u32>,
550
551 #[serde(rename = "@verticalDpi", skip_serializing_if = "Option::is_none")]
552 pub vertical_dpi: Option<u32>,
553
554 #[serde(
555 rename = "@r:id",
556 alias = "@id",
557 skip_serializing_if = "Option::is_none"
558 )]
559 pub r_id: Option<String>,
560}
561
562#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
564pub struct HeaderFooter {
565 #[serde(rename = "oddHeader", skip_serializing_if = "Option::is_none")]
566 pub odd_header: Option<String>,
567
568 #[serde(rename = "oddFooter", skip_serializing_if = "Option::is_none")]
569 pub odd_footer: Option<String>,
570}
571
572#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
574pub struct PrintOptions {
575 #[serde(rename = "@gridLines", skip_serializing_if = "Option::is_none")]
576 pub grid_lines: Option<bool>,
577
578 #[serde(rename = "@headings", skip_serializing_if = "Option::is_none")]
579 pub headings: Option<bool>,
580
581 #[serde(
582 rename = "@horizontalCentered",
583 skip_serializing_if = "Option::is_none"
584 )]
585 pub horizontal_centered: Option<bool>,
586
587 #[serde(rename = "@verticalCentered", skip_serializing_if = "Option::is_none")]
588 pub vertical_centered: Option<bool>,
589}
590
591#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
593pub struct RowBreaks {
594 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
595 pub count: Option<u32>,
596
597 #[serde(rename = "@manualBreakCount", skip_serializing_if = "Option::is_none")]
598 pub manual_break_count: Option<u32>,
599
600 #[serde(rename = "brk", default)]
601 pub brk: Vec<Break>,
602}
603
604#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
606pub struct Break {
607 #[serde(rename = "@id")]
608 pub id: u32,
609
610 #[serde(rename = "@max", skip_serializing_if = "Option::is_none")]
611 pub max: Option<u32>,
612
613 #[serde(rename = "@man", skip_serializing_if = "Option::is_none")]
614 pub man: Option<bool>,
615}
616
617#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
619pub struct DrawingRef {
620 #[serde(rename = "@r:id", alias = "@id")]
621 pub r_id: String,
622}
623
624#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
626pub struct LegacyDrawingRef {
627 #[serde(rename = "@r:id", alias = "@id")]
628 pub r_id: String,
629}
630
631#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
633pub struct TableParts {
634 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
635 pub count: Option<u32>,
636
637 #[serde(rename = "tablePart", default)]
638 pub table_parts: Vec<TablePart>,
639}
640
641#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
643pub struct TablePart {
644 #[serde(rename = "@r:id", alias = "@id")]
645 pub r_id: String,
646}
647
648#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
650pub struct ConditionalFormatting {
651 #[serde(rename = "@sqref")]
652 pub sqref: String,
653
654 #[serde(rename = "cfRule", default)]
655 pub cf_rules: Vec<CfRule>,
656}
657
658#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
660pub struct CfRule {
661 #[serde(rename = "@type")]
662 pub rule_type: String,
663
664 #[serde(rename = "@dxfId", skip_serializing_if = "Option::is_none")]
665 pub dxf_id: Option<u32>,
666
667 #[serde(rename = "@priority")]
668 pub priority: u32,
669
670 #[serde(rename = "@operator", skip_serializing_if = "Option::is_none")]
671 pub operator: Option<String>,
672
673 #[serde(rename = "@text", skip_serializing_if = "Option::is_none")]
674 pub text: Option<String>,
675
676 #[serde(rename = "@stopIfTrue", skip_serializing_if = "Option::is_none")]
677 pub stop_if_true: Option<bool>,
678
679 #[serde(rename = "@aboveAverage", skip_serializing_if = "Option::is_none")]
680 pub above_average: Option<bool>,
681
682 #[serde(rename = "@equalAverage", skip_serializing_if = "Option::is_none")]
683 pub equal_average: Option<bool>,
684
685 #[serde(rename = "@percent", skip_serializing_if = "Option::is_none")]
686 pub percent: Option<bool>,
687
688 #[serde(rename = "@rank", skip_serializing_if = "Option::is_none")]
689 pub rank: Option<u32>,
690
691 #[serde(rename = "@bottom", skip_serializing_if = "Option::is_none")]
692 pub bottom: Option<bool>,
693
694 #[serde(rename = "formula", default, skip_serializing_if = "Vec::is_empty")]
695 pub formulas: Vec<String>,
696
697 #[serde(rename = "colorScale", skip_serializing_if = "Option::is_none")]
698 pub color_scale: Option<CfColorScale>,
699
700 #[serde(rename = "dataBar", skip_serializing_if = "Option::is_none")]
701 pub data_bar: Option<CfDataBar>,
702
703 #[serde(rename = "iconSet", skip_serializing_if = "Option::is_none")]
704 pub icon_set: Option<CfIconSet>,
705}
706
707#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
709pub struct CfColorScale {
710 #[serde(rename = "cfvo", default)]
711 pub cfvos: Vec<CfVo>,
712
713 #[serde(rename = "color", default)]
714 pub colors: Vec<CfColor>,
715}
716
717#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
719pub struct CfDataBar {
720 #[serde(rename = "@showValue", skip_serializing_if = "Option::is_none")]
721 pub show_value: Option<bool>,
722
723 #[serde(rename = "cfvo", default)]
724 pub cfvos: Vec<CfVo>,
725
726 #[serde(rename = "color", skip_serializing_if = "Option::is_none")]
727 pub color: Option<CfColor>,
728}
729
730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
732pub struct CfIconSet {
733 #[serde(rename = "@iconSet", skip_serializing_if = "Option::is_none")]
734 pub icon_set: Option<String>,
735
736 #[serde(rename = "cfvo", default)]
737 pub cfvos: Vec<CfVo>,
738}
739
740#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
742pub struct CfVo {
743 #[serde(rename = "@type")]
744 pub value_type: String,
745
746 #[serde(rename = "@val", skip_serializing_if = "Option::is_none")]
747 pub val: Option<String>,
748}
749
750#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
752pub struct CfColor {
753 #[serde(rename = "@rgb", skip_serializing_if = "Option::is_none")]
754 pub rgb: Option<String>,
755
756 #[serde(rename = "@theme", skip_serializing_if = "Option::is_none")]
757 pub theme: Option<u32>,
758
759 #[serde(rename = "@tint", skip_serializing_if = "Option::is_none")]
760 pub tint: Option<f64>,
761}
762
763impl Default for WorksheetXml {
764 fn default() -> Self {
765 Self {
766 xmlns: namespaces::SPREADSHEET_ML.to_string(),
767 xmlns_r: namespaces::RELATIONSHIPS.to_string(),
768 sheet_pr: None,
769 dimension: None,
770 sheet_views: None,
771 sheet_format_pr: None,
772 cols: None,
773 sheet_data: SheetData { rows: vec![] },
774 sheet_protection: None,
775 auto_filter: None,
776 merge_cells: None,
777 conditional_formatting: vec![],
778 data_validations: None,
779 hyperlinks: None,
780 print_options: None,
781 page_margins: None,
782 page_setup: None,
783 header_footer: None,
784 row_breaks: None,
785 drawing: None,
786 legacy_drawing: None,
787 table_parts: None,
788 }
789 }
790}
791
792#[cfg(test)]
793mod tests {
794 use super::*;
795
796 #[test]
797 fn test_worksheet_default() {
798 let ws = WorksheetXml::default();
799 assert_eq!(ws.xmlns, namespaces::SPREADSHEET_ML);
800 assert_eq!(ws.xmlns_r, namespaces::RELATIONSHIPS);
801 assert!(ws.sheet_data.rows.is_empty());
802 assert!(ws.dimension.is_none());
803 assert!(ws.sheet_views.is_none());
804 assert!(ws.cols.is_none());
805 assert!(ws.merge_cells.is_none());
806 assert!(ws.page_margins.is_none());
807 assert!(ws.sheet_pr.is_none());
808 assert!(ws.sheet_protection.is_none());
809 }
810
811 #[test]
812 fn test_worksheet_roundtrip() {
813 let ws = WorksheetXml::default();
814 let xml = quick_xml::se::to_string(&ws).unwrap();
815 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
816 assert_eq!(ws.xmlns, parsed.xmlns);
817 assert_eq!(ws.xmlns_r, parsed.xmlns_r);
818 assert_eq!(ws.sheet_data.rows.len(), parsed.sheet_data.rows.len());
819 }
820
821 #[test]
822 fn test_worksheet_with_data() {
823 let ws = WorksheetXml {
824 sheet_data: SheetData {
825 rows: vec![Row {
826 r: 1,
827 spans: Some("1:3".to_string()),
828 s: None,
829 custom_format: None,
830 ht: None,
831 hidden: None,
832 custom_height: None,
833 outline_level: None,
834 cells: vec![
835 Cell {
836 r: "A1".to_string(),
837 s: None,
838 t: Some(cell_types::SHARED_STRING.to_string()),
839 v: Some("0".to_string()),
840 f: None,
841 is: None,
842 },
843 Cell {
844 r: "B1".to_string(),
845 s: None,
846 t: None,
847 v: Some("42".to_string()),
848 f: None,
849 is: None,
850 },
851 ],
852 }],
853 },
854 ..WorksheetXml::default()
855 };
856
857 let xml = quick_xml::se::to_string(&ws).unwrap();
858 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
859 assert_eq!(parsed.sheet_data.rows.len(), 1);
860 assert_eq!(parsed.sheet_data.rows[0].r, 1);
861 assert_eq!(parsed.sheet_data.rows[0].cells.len(), 2);
862 assert_eq!(parsed.sheet_data.rows[0].cells[0].r, "A1");
863 assert_eq!(parsed.sheet_data.rows[0].cells[0].t, Some("s".to_string()));
864 assert_eq!(parsed.sheet_data.rows[0].cells[0].v, Some("0".to_string()));
865 assert_eq!(parsed.sheet_data.rows[0].cells[1].r, "B1");
866 assert_eq!(parsed.sheet_data.rows[0].cells[1].v, Some("42".to_string()));
867 }
868
869 #[test]
870 fn test_cell_with_formula() {
871 let cell = Cell {
872 r: "C1".to_string(),
873 s: None,
874 t: None,
875 v: Some("84".to_string()),
876 f: Some(CellFormula {
877 t: None,
878 reference: None,
879 si: None,
880 value: Some("A1+B1".to_string()),
881 }),
882 is: None,
883 };
884 let xml = quick_xml::se::to_string(&cell).unwrap();
885 assert!(xml.contains("A1+B1"));
886 let parsed: Cell = quick_xml::de::from_str(&xml).unwrap();
887 assert!(parsed.f.is_some());
888 assert_eq!(parsed.f.unwrap().value, Some("A1+B1".to_string()));
889 }
890
891 #[test]
892 fn test_cell_with_inline_string() {
893 let cell = Cell {
894 r: "A1".to_string(),
895 s: None,
896 t: Some(cell_types::INLINE_STRING.to_string()),
897 v: None,
898 f: None,
899 is: Some(InlineString {
900 t: Some("Hello World".to_string()),
901 }),
902 };
903 let xml = quick_xml::se::to_string(&cell).unwrap();
904 assert!(xml.contains("Hello World"));
905 let parsed: Cell = quick_xml::de::from_str(&xml).unwrap();
906 assert_eq!(parsed.t, Some("inlineStr".to_string()));
907 assert!(parsed.is.is_some());
908 assert_eq!(parsed.is.unwrap().t, Some("Hello World".to_string()));
909 }
910
911 #[test]
912 fn test_parse_real_excel_worksheet() {
913 let xml = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
914<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
915 <dimension ref="A1:B2"/>
916 <sheetData>
917 <row r="1" spans="1:2">
918 <c r="A1" t="s"><v>0</v></c>
919 <c r="B1" t="s"><v>1</v></c>
920 </row>
921 <row r="2" spans="1:2">
922 <c r="A2"><v>100</v></c>
923 <c r="B2"><v>200</v></c>
924 </row>
925 </sheetData>
926</worksheet>"#;
927
928 let parsed: WorksheetXml = quick_xml::de::from_str(xml).unwrap();
929 assert_eq!(parsed.dimension.as_ref().unwrap().reference, "A1:B2");
930 assert_eq!(parsed.sheet_data.rows.len(), 2);
931 assert_eq!(parsed.sheet_data.rows[0].cells.len(), 2);
932 assert_eq!(parsed.sheet_data.rows[0].cells[0].r, "A1");
933 assert_eq!(parsed.sheet_data.rows[0].cells[0].t, Some("s".to_string()));
934 assert_eq!(parsed.sheet_data.rows[0].cells[0].v, Some("0".to_string()));
935 assert_eq!(parsed.sheet_data.rows[1].cells[0].r, "A2");
936 assert_eq!(
937 parsed.sheet_data.rows[1].cells[0].v,
938 Some("100".to_string())
939 );
940 }
941
942 #[test]
943 fn test_worksheet_with_merge_cells() {
944 let ws = WorksheetXml {
945 merge_cells: Some(MergeCells {
946 count: Some(1),
947 merge_cells: vec![MergeCell {
948 reference: "A1:B2".to_string(),
949 }],
950 }),
951 ..WorksheetXml::default()
952 };
953 let xml = quick_xml::se::to_string(&ws).unwrap();
954 assert!(xml.contains("mergeCells"));
955 assert!(xml.contains("A1:B2"));
956 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
957 assert!(parsed.merge_cells.is_some());
958 assert_eq!(parsed.merge_cells.as_ref().unwrap().merge_cells.len(), 1);
959 }
960
961 #[test]
962 fn test_empty_sheet_data_serialization() {
963 let sd = SheetData { rows: vec![] };
964 let xml = quick_xml::se::to_string(&sd).unwrap();
965 let parsed: SheetData = quick_xml::de::from_str(&xml).unwrap();
967 assert!(parsed.rows.is_empty());
968 }
969
970 #[test]
971 fn test_row_optional_fields_not_serialized() {
972 let row = Row {
973 r: 1,
974 spans: None,
975 s: None,
976 custom_format: None,
977 ht: None,
978 hidden: None,
979 custom_height: None,
980 outline_level: None,
981 cells: vec![],
982 };
983 let xml = quick_xml::se::to_string(&row).unwrap();
984 assert!(!xml.contains("spans"));
985 assert!(!xml.contains("ht"));
986 assert!(!xml.contains("hidden"));
987 }
988
989 #[test]
990 fn test_cell_types_constants() {
991 assert_eq!(cell_types::BOOLEAN, "b");
992 assert_eq!(cell_types::DATE, "d");
993 assert_eq!(cell_types::ERROR, "e");
994 assert_eq!(cell_types::INLINE_STRING, "inlineStr");
995 assert_eq!(cell_types::NUMBER, "n");
996 assert_eq!(cell_types::SHARED_STRING, "s");
997 assert_eq!(cell_types::FORMULA_STRING, "str");
998 }
999
1000 #[test]
1001 fn test_worksheet_with_cols() {
1002 let ws = WorksheetXml {
1003 cols: Some(Cols {
1004 cols: vec![Col {
1005 min: 1,
1006 max: 1,
1007 width: Some(15.0),
1008 style: None,
1009 hidden: None,
1010 custom_width: Some(true),
1011 outline_level: None,
1012 }],
1013 }),
1014 ..WorksheetXml::default()
1015 };
1016 let xml = quick_xml::se::to_string(&ws).unwrap();
1017 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
1018 assert!(parsed.cols.is_some());
1019 let cols = parsed.cols.unwrap();
1020 assert_eq!(cols.cols.len(), 1);
1021 assert_eq!(cols.cols[0].min, 1);
1022 assert_eq!(cols.cols[0].width, Some(15.0));
1023 assert_eq!(cols.cols[0].custom_width, Some(true));
1024 }
1025
1026 #[test]
1027 fn test_sheet_protection_roundtrip() {
1028 let prot = SheetProtection {
1029 password: Some("ABCD".to_string()),
1030 sheet: Some(true),
1031 objects: Some(true),
1032 scenarios: Some(true),
1033 format_cells: Some(false),
1034 ..SheetProtection::default()
1035 };
1036 let xml = quick_xml::se::to_string(&prot).unwrap();
1037 let parsed: SheetProtection = quick_xml::de::from_str(&xml).unwrap();
1038 assert_eq!(parsed.password, Some("ABCD".to_string()));
1039 assert_eq!(parsed.sheet, Some(true));
1040 assert_eq!(parsed.objects, Some(true));
1041 assert_eq!(parsed.scenarios, Some(true));
1042 assert_eq!(parsed.format_cells, Some(false));
1043 assert!(parsed.sort.is_none());
1044 }
1045
1046 #[test]
1047 fn test_sheet_pr_roundtrip() {
1048 let pr = SheetPr {
1049 code_name: Some("Sheet1".to_string()),
1050 tab_color: Some(TabColor {
1051 rgb: Some("FF0000".to_string()),
1052 theme: None,
1053 indexed: None,
1054 }),
1055 ..SheetPr::default()
1056 };
1057 let xml = quick_xml::se::to_string(&pr).unwrap();
1058 let parsed: SheetPr = quick_xml::de::from_str(&xml).unwrap();
1059 assert_eq!(parsed.code_name, Some("Sheet1".to_string()));
1060 assert!(parsed.tab_color.is_some());
1061 assert_eq!(parsed.tab_color.unwrap().rgb, Some("FF0000".to_string()));
1062 }
1063
1064 #[test]
1065 fn test_sheet_format_pr_extended_fields() {
1066 let fmt = SheetFormatPr {
1067 default_row_height: 15.0,
1068 default_col_width: Some(10.0),
1069 custom_height: Some(true),
1070 outline_level_row: Some(2),
1071 outline_level_col: Some(1),
1072 };
1073 let xml = quick_xml::se::to_string(&fmt).unwrap();
1074 let parsed: SheetFormatPr = quick_xml::de::from_str(&xml).unwrap();
1075 assert_eq!(parsed.default_row_height, 15.0);
1076 assert_eq!(parsed.default_col_width, Some(10.0));
1077 assert_eq!(parsed.custom_height, Some(true));
1078 assert_eq!(parsed.outline_level_row, Some(2));
1079 assert_eq!(parsed.outline_level_col, Some(1));
1080 }
1081}