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(
412 rename = "@disablePrompts",
413 skip_serializing_if = "Option::is_none",
414 default
415 )]
416 pub disable_prompts: Option<bool>,
417
418 #[serde(rename = "@xWindow", skip_serializing_if = "Option::is_none", default)]
419 pub x_window: Option<u32>,
420
421 #[serde(rename = "@yWindow", skip_serializing_if = "Option::is_none", default)]
422 pub y_window: Option<u32>,
423
424 #[serde(rename = "dataValidation", default)]
425 pub data_validations: Vec<DataValidation>,
426}
427
428#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
430pub struct DataValidation {
431 #[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
432 pub validation_type: Option<String>,
433
434 #[serde(rename = "@operator", skip_serializing_if = "Option::is_none")]
435 pub operator: Option<String>,
436
437 #[serde(rename = "@allowBlank", skip_serializing_if = "Option::is_none")]
438 pub allow_blank: Option<bool>,
439
440 #[serde(
441 rename = "@showDropDown",
442 skip_serializing_if = "Option::is_none",
443 default
444 )]
445 pub show_drop_down: Option<bool>,
446
447 #[serde(rename = "@showInputMessage", skip_serializing_if = "Option::is_none")]
448 pub show_input_message: Option<bool>,
449
450 #[serde(rename = "@showErrorMessage", skip_serializing_if = "Option::is_none")]
451 pub show_error_message: Option<bool>,
452
453 #[serde(rename = "@errorStyle", skip_serializing_if = "Option::is_none")]
454 pub error_style: Option<String>,
455
456 #[serde(rename = "@imeMode", skip_serializing_if = "Option::is_none", default)]
457 pub ime_mode: Option<String>,
458
459 #[serde(rename = "@errorTitle", skip_serializing_if = "Option::is_none")]
460 pub error_title: Option<String>,
461
462 #[serde(rename = "@error", skip_serializing_if = "Option::is_none")]
463 pub error: Option<String>,
464
465 #[serde(rename = "@promptTitle", skip_serializing_if = "Option::is_none")]
466 pub prompt_title: Option<String>,
467
468 #[serde(rename = "@prompt", skip_serializing_if = "Option::is_none")]
469 pub prompt: Option<String>,
470
471 #[serde(rename = "@sqref")]
472 pub sqref: String,
473
474 #[serde(rename = "formula1", skip_serializing_if = "Option::is_none")]
475 pub formula1: Option<String>,
476
477 #[serde(rename = "formula2", skip_serializing_if = "Option::is_none")]
478 pub formula2: Option<String>,
479}
480
481#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
483pub struct MergeCells {
484 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
485 pub count: Option<u32>,
486
487 #[serde(rename = "mergeCell", default)]
488 pub merge_cells: Vec<MergeCell>,
489}
490
491#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
493pub struct MergeCell {
494 #[serde(rename = "@ref")]
495 pub reference: String,
496}
497
498#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
500pub struct Hyperlinks {
501 #[serde(rename = "hyperlink", default)]
502 pub hyperlinks: Vec<Hyperlink>,
503}
504
505#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
507pub struct Hyperlink {
508 #[serde(rename = "@ref")]
509 pub reference: String,
510
511 #[serde(
512 rename = "@r:id",
513 alias = "@id",
514 skip_serializing_if = "Option::is_none"
515 )]
516 pub r_id: Option<String>,
517
518 #[serde(rename = "@location", skip_serializing_if = "Option::is_none")]
519 pub location: Option<String>,
520
521 #[serde(rename = "@display", skip_serializing_if = "Option::is_none")]
522 pub display: Option<String>,
523
524 #[serde(rename = "@tooltip", skip_serializing_if = "Option::is_none")]
525 pub tooltip: Option<String>,
526}
527
528#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
530pub struct PageMargins {
531 #[serde(rename = "@left")]
532 pub left: f64,
533
534 #[serde(rename = "@right")]
535 pub right: f64,
536
537 #[serde(rename = "@top")]
538 pub top: f64,
539
540 #[serde(rename = "@bottom")]
541 pub bottom: f64,
542
543 #[serde(rename = "@header")]
544 pub header: f64,
545
546 #[serde(rename = "@footer")]
547 pub footer: f64,
548}
549
550#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
552pub struct PageSetup {
553 #[serde(rename = "@paperSize", skip_serializing_if = "Option::is_none")]
554 pub paper_size: Option<u32>,
555
556 #[serde(rename = "@orientation", skip_serializing_if = "Option::is_none")]
557 pub orientation: Option<String>,
558
559 #[serde(rename = "@scale", skip_serializing_if = "Option::is_none")]
560 pub scale: Option<u32>,
561
562 #[serde(rename = "@fitToWidth", skip_serializing_if = "Option::is_none")]
563 pub fit_to_width: Option<u32>,
564
565 #[serde(rename = "@fitToHeight", skip_serializing_if = "Option::is_none")]
566 pub fit_to_height: Option<u32>,
567
568 #[serde(rename = "@firstPageNumber", skip_serializing_if = "Option::is_none")]
569 pub first_page_number: Option<u32>,
570
571 #[serde(rename = "@horizontalDpi", skip_serializing_if = "Option::is_none")]
572 pub horizontal_dpi: Option<u32>,
573
574 #[serde(rename = "@verticalDpi", skip_serializing_if = "Option::is_none")]
575 pub vertical_dpi: Option<u32>,
576
577 #[serde(
578 rename = "@r:id",
579 alias = "@id",
580 skip_serializing_if = "Option::is_none"
581 )]
582 pub r_id: Option<String>,
583}
584
585#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
587pub struct HeaderFooter {
588 #[serde(rename = "oddHeader", skip_serializing_if = "Option::is_none")]
589 pub odd_header: Option<String>,
590
591 #[serde(rename = "oddFooter", skip_serializing_if = "Option::is_none")]
592 pub odd_footer: Option<String>,
593}
594
595#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
597pub struct PrintOptions {
598 #[serde(rename = "@gridLines", skip_serializing_if = "Option::is_none")]
599 pub grid_lines: Option<bool>,
600
601 #[serde(rename = "@headings", skip_serializing_if = "Option::is_none")]
602 pub headings: Option<bool>,
603
604 #[serde(
605 rename = "@horizontalCentered",
606 skip_serializing_if = "Option::is_none"
607 )]
608 pub horizontal_centered: Option<bool>,
609
610 #[serde(rename = "@verticalCentered", skip_serializing_if = "Option::is_none")]
611 pub vertical_centered: Option<bool>,
612}
613
614#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
616pub struct RowBreaks {
617 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
618 pub count: Option<u32>,
619
620 #[serde(rename = "@manualBreakCount", skip_serializing_if = "Option::is_none")]
621 pub manual_break_count: Option<u32>,
622
623 #[serde(rename = "brk", default)]
624 pub brk: Vec<Break>,
625}
626
627#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
629pub struct Break {
630 #[serde(rename = "@id")]
631 pub id: u32,
632
633 #[serde(rename = "@max", skip_serializing_if = "Option::is_none")]
634 pub max: Option<u32>,
635
636 #[serde(rename = "@man", skip_serializing_if = "Option::is_none")]
637 pub man: Option<bool>,
638}
639
640#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
642pub struct DrawingRef {
643 #[serde(rename = "@r:id", alias = "@id")]
644 pub r_id: String,
645}
646
647#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
649pub struct LegacyDrawingRef {
650 #[serde(rename = "@r:id", alias = "@id")]
651 pub r_id: String,
652}
653
654#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
656pub struct TableParts {
657 #[serde(rename = "@count", skip_serializing_if = "Option::is_none")]
658 pub count: Option<u32>,
659
660 #[serde(rename = "tablePart", default)]
661 pub table_parts: Vec<TablePart>,
662}
663
664#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
666pub struct TablePart {
667 #[serde(rename = "@r:id", alias = "@id")]
668 pub r_id: String,
669}
670
671#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
673pub struct ConditionalFormatting {
674 #[serde(rename = "@sqref")]
675 pub sqref: String,
676
677 #[serde(rename = "cfRule", default)]
678 pub cf_rules: Vec<CfRule>,
679}
680
681#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
683pub struct CfRule {
684 #[serde(rename = "@type")]
685 pub rule_type: String,
686
687 #[serde(rename = "@dxfId", skip_serializing_if = "Option::is_none")]
688 pub dxf_id: Option<u32>,
689
690 #[serde(rename = "@priority")]
691 pub priority: u32,
692
693 #[serde(rename = "@operator", skip_serializing_if = "Option::is_none")]
694 pub operator: Option<String>,
695
696 #[serde(rename = "@text", skip_serializing_if = "Option::is_none")]
697 pub text: Option<String>,
698
699 #[serde(rename = "@stopIfTrue", skip_serializing_if = "Option::is_none")]
700 pub stop_if_true: Option<bool>,
701
702 #[serde(rename = "@aboveAverage", skip_serializing_if = "Option::is_none")]
703 pub above_average: Option<bool>,
704
705 #[serde(rename = "@equalAverage", skip_serializing_if = "Option::is_none")]
706 pub equal_average: Option<bool>,
707
708 #[serde(rename = "@percent", skip_serializing_if = "Option::is_none")]
709 pub percent: Option<bool>,
710
711 #[serde(rename = "@rank", skip_serializing_if = "Option::is_none")]
712 pub rank: Option<u32>,
713
714 #[serde(rename = "@bottom", skip_serializing_if = "Option::is_none")]
715 pub bottom: Option<bool>,
716
717 #[serde(rename = "formula", default, skip_serializing_if = "Vec::is_empty")]
718 pub formulas: Vec<String>,
719
720 #[serde(rename = "colorScale", skip_serializing_if = "Option::is_none")]
721 pub color_scale: Option<CfColorScale>,
722
723 #[serde(rename = "dataBar", skip_serializing_if = "Option::is_none")]
724 pub data_bar: Option<CfDataBar>,
725
726 #[serde(rename = "iconSet", skip_serializing_if = "Option::is_none")]
727 pub icon_set: Option<CfIconSet>,
728}
729
730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
732pub struct CfColorScale {
733 #[serde(rename = "cfvo", default)]
734 pub cfvos: Vec<CfVo>,
735
736 #[serde(rename = "color", default)]
737 pub colors: Vec<CfColor>,
738}
739
740#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
742pub struct CfDataBar {
743 #[serde(rename = "@showValue", skip_serializing_if = "Option::is_none")]
744 pub show_value: Option<bool>,
745
746 #[serde(rename = "cfvo", default)]
747 pub cfvos: Vec<CfVo>,
748
749 #[serde(rename = "color", skip_serializing_if = "Option::is_none")]
750 pub color: Option<CfColor>,
751}
752
753#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
755pub struct CfIconSet {
756 #[serde(rename = "@iconSet", skip_serializing_if = "Option::is_none")]
757 pub icon_set: Option<String>,
758
759 #[serde(rename = "cfvo", default)]
760 pub cfvos: Vec<CfVo>,
761}
762
763#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
765pub struct CfVo {
766 #[serde(rename = "@type")]
767 pub value_type: String,
768
769 #[serde(rename = "@val", skip_serializing_if = "Option::is_none")]
770 pub val: Option<String>,
771}
772
773#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
775pub struct CfColor {
776 #[serde(rename = "@rgb", skip_serializing_if = "Option::is_none")]
777 pub rgb: Option<String>,
778
779 #[serde(rename = "@theme", skip_serializing_if = "Option::is_none")]
780 pub theme: Option<u32>,
781
782 #[serde(rename = "@tint", skip_serializing_if = "Option::is_none")]
783 pub tint: Option<f64>,
784}
785
786impl Default for WorksheetXml {
787 fn default() -> Self {
788 Self {
789 xmlns: namespaces::SPREADSHEET_ML.to_string(),
790 xmlns_r: namespaces::RELATIONSHIPS.to_string(),
791 sheet_pr: None,
792 dimension: None,
793 sheet_views: None,
794 sheet_format_pr: None,
795 cols: None,
796 sheet_data: SheetData { rows: vec![] },
797 sheet_protection: None,
798 auto_filter: None,
799 merge_cells: None,
800 conditional_formatting: vec![],
801 data_validations: None,
802 hyperlinks: None,
803 print_options: None,
804 page_margins: None,
805 page_setup: None,
806 header_footer: None,
807 row_breaks: None,
808 drawing: None,
809 legacy_drawing: None,
810 table_parts: None,
811 }
812 }
813}
814
815#[cfg(test)]
816mod tests {
817 use super::*;
818
819 #[test]
820 fn test_worksheet_default() {
821 let ws = WorksheetXml::default();
822 assert_eq!(ws.xmlns, namespaces::SPREADSHEET_ML);
823 assert_eq!(ws.xmlns_r, namespaces::RELATIONSHIPS);
824 assert!(ws.sheet_data.rows.is_empty());
825 assert!(ws.dimension.is_none());
826 assert!(ws.sheet_views.is_none());
827 assert!(ws.cols.is_none());
828 assert!(ws.merge_cells.is_none());
829 assert!(ws.page_margins.is_none());
830 assert!(ws.sheet_pr.is_none());
831 assert!(ws.sheet_protection.is_none());
832 }
833
834 #[test]
835 fn test_worksheet_roundtrip() {
836 let ws = WorksheetXml::default();
837 let xml = quick_xml::se::to_string(&ws).unwrap();
838 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
839 assert_eq!(ws.xmlns, parsed.xmlns);
840 assert_eq!(ws.xmlns_r, parsed.xmlns_r);
841 assert_eq!(ws.sheet_data.rows.len(), parsed.sheet_data.rows.len());
842 }
843
844 #[test]
845 fn test_worksheet_with_data() {
846 let ws = WorksheetXml {
847 sheet_data: SheetData {
848 rows: vec![Row {
849 r: 1,
850 spans: Some("1:3".to_string()),
851 s: None,
852 custom_format: None,
853 ht: None,
854 hidden: None,
855 custom_height: None,
856 outline_level: None,
857 cells: vec![
858 Cell {
859 r: "A1".to_string(),
860 s: None,
861 t: Some(cell_types::SHARED_STRING.to_string()),
862 v: Some("0".to_string()),
863 f: None,
864 is: None,
865 },
866 Cell {
867 r: "B1".to_string(),
868 s: None,
869 t: None,
870 v: Some("42".to_string()),
871 f: None,
872 is: None,
873 },
874 ],
875 }],
876 },
877 ..WorksheetXml::default()
878 };
879
880 let xml = quick_xml::se::to_string(&ws).unwrap();
881 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
882 assert_eq!(parsed.sheet_data.rows.len(), 1);
883 assert_eq!(parsed.sheet_data.rows[0].r, 1);
884 assert_eq!(parsed.sheet_data.rows[0].cells.len(), 2);
885 assert_eq!(parsed.sheet_data.rows[0].cells[0].r, "A1");
886 assert_eq!(parsed.sheet_data.rows[0].cells[0].t, Some("s".to_string()));
887 assert_eq!(parsed.sheet_data.rows[0].cells[0].v, Some("0".to_string()));
888 assert_eq!(parsed.sheet_data.rows[0].cells[1].r, "B1");
889 assert_eq!(parsed.sheet_data.rows[0].cells[1].v, Some("42".to_string()));
890 }
891
892 #[test]
893 fn test_cell_with_formula() {
894 let cell = Cell {
895 r: "C1".to_string(),
896 s: None,
897 t: None,
898 v: Some("84".to_string()),
899 f: Some(CellFormula {
900 t: None,
901 reference: None,
902 si: None,
903 value: Some("A1+B1".to_string()),
904 }),
905 is: None,
906 };
907 let xml = quick_xml::se::to_string(&cell).unwrap();
908 assert!(xml.contains("A1+B1"));
909 let parsed: Cell = quick_xml::de::from_str(&xml).unwrap();
910 assert!(parsed.f.is_some());
911 assert_eq!(parsed.f.unwrap().value, Some("A1+B1".to_string()));
912 }
913
914 #[test]
915 fn test_cell_with_inline_string() {
916 let cell = Cell {
917 r: "A1".to_string(),
918 s: None,
919 t: Some(cell_types::INLINE_STRING.to_string()),
920 v: None,
921 f: None,
922 is: Some(InlineString {
923 t: Some("Hello World".to_string()),
924 }),
925 };
926 let xml = quick_xml::se::to_string(&cell).unwrap();
927 assert!(xml.contains("Hello World"));
928 let parsed: Cell = quick_xml::de::from_str(&xml).unwrap();
929 assert_eq!(parsed.t, Some("inlineStr".to_string()));
930 assert!(parsed.is.is_some());
931 assert_eq!(parsed.is.unwrap().t, Some("Hello World".to_string()));
932 }
933
934 #[test]
935 fn test_parse_real_excel_worksheet() {
936 let xml = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
937<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
938 <dimension ref="A1:B2"/>
939 <sheetData>
940 <row r="1" spans="1:2">
941 <c r="A1" t="s"><v>0</v></c>
942 <c r="B1" t="s"><v>1</v></c>
943 </row>
944 <row r="2" spans="1:2">
945 <c r="A2"><v>100</v></c>
946 <c r="B2"><v>200</v></c>
947 </row>
948 </sheetData>
949</worksheet>"#;
950
951 let parsed: WorksheetXml = quick_xml::de::from_str(xml).unwrap();
952 assert_eq!(parsed.dimension.as_ref().unwrap().reference, "A1:B2");
953 assert_eq!(parsed.sheet_data.rows.len(), 2);
954 assert_eq!(parsed.sheet_data.rows[0].cells.len(), 2);
955 assert_eq!(parsed.sheet_data.rows[0].cells[0].r, "A1");
956 assert_eq!(parsed.sheet_data.rows[0].cells[0].t, Some("s".to_string()));
957 assert_eq!(parsed.sheet_data.rows[0].cells[0].v, Some("0".to_string()));
958 assert_eq!(parsed.sheet_data.rows[1].cells[0].r, "A2");
959 assert_eq!(
960 parsed.sheet_data.rows[1].cells[0].v,
961 Some("100".to_string())
962 );
963 }
964
965 #[test]
966 fn test_worksheet_with_merge_cells() {
967 let ws = WorksheetXml {
968 merge_cells: Some(MergeCells {
969 count: Some(1),
970 merge_cells: vec![MergeCell {
971 reference: "A1:B2".to_string(),
972 }],
973 }),
974 ..WorksheetXml::default()
975 };
976 let xml = quick_xml::se::to_string(&ws).unwrap();
977 assert!(xml.contains("mergeCells"));
978 assert!(xml.contains("A1:B2"));
979 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
980 assert!(parsed.merge_cells.is_some());
981 assert_eq!(parsed.merge_cells.as_ref().unwrap().merge_cells.len(), 1);
982 }
983
984 #[test]
985 fn test_empty_sheet_data_serialization() {
986 let sd = SheetData { rows: vec![] };
987 let xml = quick_xml::se::to_string(&sd).unwrap();
988 let parsed: SheetData = quick_xml::de::from_str(&xml).unwrap();
990 assert!(parsed.rows.is_empty());
991 }
992
993 #[test]
994 fn test_row_optional_fields_not_serialized() {
995 let row = Row {
996 r: 1,
997 spans: None,
998 s: None,
999 custom_format: None,
1000 ht: None,
1001 hidden: None,
1002 custom_height: None,
1003 outline_level: None,
1004 cells: vec![],
1005 };
1006 let xml = quick_xml::se::to_string(&row).unwrap();
1007 assert!(!xml.contains("spans"));
1008 assert!(!xml.contains("ht"));
1009 assert!(!xml.contains("hidden"));
1010 }
1011
1012 #[test]
1013 fn test_cell_types_constants() {
1014 assert_eq!(cell_types::BOOLEAN, "b");
1015 assert_eq!(cell_types::DATE, "d");
1016 assert_eq!(cell_types::ERROR, "e");
1017 assert_eq!(cell_types::INLINE_STRING, "inlineStr");
1018 assert_eq!(cell_types::NUMBER, "n");
1019 assert_eq!(cell_types::SHARED_STRING, "s");
1020 assert_eq!(cell_types::FORMULA_STRING, "str");
1021 }
1022
1023 #[test]
1024 fn test_worksheet_with_cols() {
1025 let ws = WorksheetXml {
1026 cols: Some(Cols {
1027 cols: vec![Col {
1028 min: 1,
1029 max: 1,
1030 width: Some(15.0),
1031 style: None,
1032 hidden: None,
1033 custom_width: Some(true),
1034 outline_level: None,
1035 }],
1036 }),
1037 ..WorksheetXml::default()
1038 };
1039 let xml = quick_xml::se::to_string(&ws).unwrap();
1040 let parsed: WorksheetXml = quick_xml::de::from_str(&xml).unwrap();
1041 assert!(parsed.cols.is_some());
1042 let cols = parsed.cols.unwrap();
1043 assert_eq!(cols.cols.len(), 1);
1044 assert_eq!(cols.cols[0].min, 1);
1045 assert_eq!(cols.cols[0].width, Some(15.0));
1046 assert_eq!(cols.cols[0].custom_width, Some(true));
1047 }
1048
1049 #[test]
1050 fn test_sheet_protection_roundtrip() {
1051 let prot = SheetProtection {
1052 password: Some("ABCD".to_string()),
1053 sheet: Some(true),
1054 objects: Some(true),
1055 scenarios: Some(true),
1056 format_cells: Some(false),
1057 ..SheetProtection::default()
1058 };
1059 let xml = quick_xml::se::to_string(&prot).unwrap();
1060 let parsed: SheetProtection = quick_xml::de::from_str(&xml).unwrap();
1061 assert_eq!(parsed.password, Some("ABCD".to_string()));
1062 assert_eq!(parsed.sheet, Some(true));
1063 assert_eq!(parsed.objects, Some(true));
1064 assert_eq!(parsed.scenarios, Some(true));
1065 assert_eq!(parsed.format_cells, Some(false));
1066 assert!(parsed.sort.is_none());
1067 }
1068
1069 #[test]
1070 fn test_sheet_pr_roundtrip() {
1071 let pr = SheetPr {
1072 code_name: Some("Sheet1".to_string()),
1073 tab_color: Some(TabColor {
1074 rgb: Some("FF0000".to_string()),
1075 theme: None,
1076 indexed: None,
1077 }),
1078 ..SheetPr::default()
1079 };
1080 let xml = quick_xml::se::to_string(&pr).unwrap();
1081 let parsed: SheetPr = quick_xml::de::from_str(&xml).unwrap();
1082 assert_eq!(parsed.code_name, Some("Sheet1".to_string()));
1083 assert!(parsed.tab_color.is_some());
1084 assert_eq!(parsed.tab_color.unwrap().rgb, Some("FF0000".to_string()));
1085 }
1086
1087 #[test]
1088 fn test_sheet_format_pr_extended_fields() {
1089 let fmt = SheetFormatPr {
1090 default_row_height: 15.0,
1091 default_col_width: Some(10.0),
1092 custom_height: Some(true),
1093 outline_level_row: Some(2),
1094 outline_level_col: Some(1),
1095 };
1096 let xml = quick_xml::se::to_string(&fmt).unwrap();
1097 let parsed: SheetFormatPr = quick_xml::de::from_str(&xml).unwrap();
1098 assert_eq!(parsed.default_row_height, 15.0);
1099 assert_eq!(parsed.default_col_width, Some(10.0));
1100 assert_eq!(parsed.custom_height, Some(true));
1101 assert_eq!(parsed.outline_level_row, Some(2));
1102 assert_eq!(parsed.outline_level_col, Some(1));
1103 }
1104}