1use xml_core::{BytesStart, Event, Reader};
15
16use crate::error::{Error, Result};
17use crate::model::{
18 Area3DChart, AreaChart, AreaSeries, Axis, AxisDataSource, AxisPosition, Bar3DChart, Bar3DShape,
19 BarChart, BarDirection, BarGrouping, BarSeries, CategoryAxis, Chart, ChartSpace, ChartType,
20 CrossBetween, DisplayBlanksAs, DoughnutChart, Legend, LegendPosition, Line3DChart, LineChart,
21 LineGrouping, LineSeries, Marker, MarkerSymbol, NumericData, NumericDataSource, NumericPoint,
22 Pie3DChart, PieChart, PieSeries, PlotArea, ScatterChart, ScatterSeries, ScatterStyle,
23 SeriesTitle, StringData, StringDataSource, StringPoint, Surface, Surface3DChart, SurfaceSeries,
24 Title, TitleText, ValueAxis, View3D,
25};
26
27pub fn read_chart_space(xml: &str) -> Result<ChartSpace> {
29 let mut reader = Reader::from_xml_str(xml);
30 loop {
31 match reader.read_event()? {
32 Event::Start(start) if start.local_name().as_ref() == b"chartSpace" => {
33 return parse_chart_space(&mut reader);
34 }
35 Event::Eof => return Err(Error::MissingChartSpace),
36 _ => {}
37 }
38 }
39}
40
41fn parse_chart_space(reader: &mut Reader) -> Result<ChartSpace> {
42 let mut chart = None;
43 let mut shape_properties = None;
44
45 loop {
46 match reader.read_event()? {
47 Event::Start(start) if start.local_name().as_ref() == b"chart" => {
48 chart = Some(parse_chart(reader)?);
49 }
50 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
51 shape_properties = Some(drawing::read_shape_properties(reader)?);
52 }
53 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
54 shape_properties = Some(drawing::ShapeProperties::new());
55 }
56 Event::Start(_) => skip_subtree(reader)?,
60 Event::Empty(_) => {}
61 Event::End(end) if end.local_name().as_ref() == b"chartSpace" => break,
62 Event::Eof => break,
63 _ => {}
64 }
65 }
66
67 let chart = chart.unwrap_or_else(|| Chart::new(PlotArea::new()));
68 let mut chart_space = ChartSpace::new(chart);
69 chart_space.shape_properties = shape_properties;
70 Ok(chart_space)
71}
72
73fn skip_subtree(reader: &mut Reader) -> Result<()> {
75 let mut depth: u32 = 0;
76 loop {
77 match reader.read_event()? {
78 Event::Start(_) => depth += 1,
79 Event::End(_) => {
80 if depth == 0 {
81 return Ok(());
82 }
83 depth -= 1;
84 }
85 Event::Eof => return Ok(()),
86 _ => {}
87 }
88 }
89}
90
91fn raw_attribute(start: &BytesStart, name: &[u8]) -> Option<String> {
92 start
93 .attributes()
94 .flatten()
95 .find(|attribute| attribute.key.local_name().as_ref() == name)
96 .and_then(|attribute| {
97 xml_core::decode_attribute_value(attribute.value.as_ref())
98 .ok()
99 .flatten()
100 })
101}
102
103fn parse_bool_val(start: &BytesStart) -> Option<bool> {
104 raw_attribute(start, b"val").map(|value| value == "1" || value == "true")
105}
106
107fn read_text_content(reader: &mut Reader, end_local_name: &[u8]) -> Result<String> {
111 let mut text = String::new();
112 loop {
113 match reader.read_event()? {
114 Event::Text(content) => text.push_str(&xml_core::decode_text(&content)?),
115 Event::GeneralRef(reference) => {
116 if let Some(resolved) = xml_core::decode_general_ref(&reference)? {
117 text.push_str(&resolved);
118 }
119 }
120 Event::End(end) if end.local_name().as_ref() == end_local_name => break,
121 Event::Eof => break,
122 _ => {}
123 }
124 }
125 Ok(text)
126}
127
128fn parse_percent(value: &str) -> Option<i32> {
131 value.strip_suffix('%').unwrap_or(value).parse().ok()
132}
133
134fn parse_chart(reader: &mut Reader) -> Result<Chart> {
135 let mut title = None;
136 let mut auto_title_deleted = None;
137 let mut view_3d = None;
138 let mut floor = None;
139 let mut side_wall = None;
140 let mut back_wall = None;
141 let mut plot_area = None;
142 let mut legend = None;
143 let mut plot_visible_only = None;
144 let mut display_blanks_as = None;
145
146 loop {
147 match reader.read_event()? {
148 Event::Start(start) if start.local_name().as_ref() == b"title" => {
149 title = Some(parse_title(reader)?);
150 }
151 Event::Empty(start) if start.local_name().as_ref() == b"title" => {
152 title = Some(Title::new());
153 }
154
155 Event::Empty(child) if child.local_name().as_ref() == b"autoTitleDeleted" => {
156 auto_title_deleted = parse_bool_val(&child);
157 }
158 Event::Start(child) if child.local_name().as_ref() == b"autoTitleDeleted" => {
159 auto_title_deleted = parse_bool_val(&child);
160 skip_subtree(reader)?;
161 }
162
163 Event::Start(start) if start.local_name().as_ref() == b"view3D" => {
164 view_3d = Some(parse_view_3d(reader)?);
165 }
166 Event::Empty(start) if start.local_name().as_ref() == b"view3D" => {
167 view_3d = Some(View3D::new());
168 }
169
170 Event::Start(start) if start.local_name().as_ref() == b"floor" => {
171 floor = Some(parse_surface(reader)?);
172 }
173 Event::Empty(start) if start.local_name().as_ref() == b"floor" => {
174 floor = Some(Surface::new());
175 }
176 Event::Start(start) if start.local_name().as_ref() == b"sideWall" => {
177 side_wall = Some(parse_surface(reader)?);
178 }
179 Event::Empty(start) if start.local_name().as_ref() == b"sideWall" => {
180 side_wall = Some(Surface::new());
181 }
182 Event::Start(start) if start.local_name().as_ref() == b"backWall" => {
183 back_wall = Some(parse_surface(reader)?);
184 }
185 Event::Empty(start) if start.local_name().as_ref() == b"backWall" => {
186 back_wall = Some(Surface::new());
187 }
188
189 Event::Start(start) if start.local_name().as_ref() == b"plotArea" => {
190 plot_area = Some(parse_plot_area(reader)?);
191 }
192
193 Event::Start(start) if start.local_name().as_ref() == b"legend" => {
194 legend = Some(parse_legend(reader)?);
195 }
196 Event::Empty(start) if start.local_name().as_ref() == b"legend" => {
197 legend = Some(Legend::new());
198 }
199
200 Event::Empty(child) if child.local_name().as_ref() == b"plotVisOnly" => {
201 plot_visible_only = parse_bool_val(&child);
202 }
203 Event::Start(child) if child.local_name().as_ref() == b"plotVisOnly" => {
204 plot_visible_only = parse_bool_val(&child);
205 skip_subtree(reader)?;
206 }
207
208 Event::Empty(child) if child.local_name().as_ref() == b"dispBlanksAs" => {
209 display_blanks_as =
210 raw_attribute(&child, b"val").and_then(|v| DisplayBlanksAs::from_xml_token(&v));
211 }
212 Event::Start(child) if child.local_name().as_ref() == b"dispBlanksAs" => {
213 display_blanks_as =
214 raw_attribute(&child, b"val").and_then(|v| DisplayBlanksAs::from_xml_token(&v));
215 skip_subtree(reader)?;
216 }
217
218 Event::Start(_) => skip_subtree(reader)?,
220 Event::Empty(_) => {}
221 Event::End(end) if end.local_name().as_ref() == b"chart" => break,
222 Event::Eof => break,
223 _ => {}
224 }
225 }
226
227 let mut chart = Chart::new(plot_area.unwrap_or_else(PlotArea::new));
228 chart.title = title;
229 chart.auto_title_deleted = auto_title_deleted;
230 chart.view_3d = view_3d;
231 chart.floor = floor;
232 chart.side_wall = side_wall;
233 chart.back_wall = back_wall;
234 chart.legend = legend;
235 chart.plot_visible_only = plot_visible_only;
236 chart.display_blanks_as = display_blanks_as;
237 Ok(chart)
238}
239
240fn parse_title(reader: &mut Reader) -> Result<Title> {
241 let mut title = Title::new();
242
243 loop {
244 match reader.read_event()? {
245 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
246 title.text = Some(parse_title_text(reader)?);
247 }
248
249 Event::Empty(child) if child.local_name().as_ref() == b"overlay" => {
250 title.overlay = parse_bool_val(&child);
251 }
252 Event::Start(child) if child.local_name().as_ref() == b"overlay" => {
253 title.overlay = parse_bool_val(&child);
254 skip_subtree(reader)?;
255 }
256
257 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
258 title.shape_properties = Some(drawing::read_shape_properties(reader)?);
259 }
260 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
261 title.shape_properties = Some(drawing::ShapeProperties::new());
262 }
263
264 Event::Start(_) => skip_subtree(reader)?,
267 Event::Empty(_) => {}
268 Event::End(_) | Event::Eof => break,
269 _ => {}
270 }
271 }
272
273 Ok(title)
274}
275
276fn parse_title_text(reader: &mut Reader) -> Result<TitleText> {
277 let mut result = None;
278
279 loop {
280 match reader.read_event()? {
281 Event::Start(start) if start.local_name().as_ref() == b"strRef" => {
282 let (formula, cache) = parse_simple_string_reference(reader)?;
283 result = Some(TitleText::Reference { formula, cache });
284 }
285 Event::Start(start) if start.local_name().as_ref() == b"rich" => {
286 result = Some(TitleText::Rich(drawing::read_text_body(reader)?));
287 }
288 Event::Start(_) => skip_subtree(reader)?,
289 Event::End(end) if end.local_name().as_ref() == b"tx" => break,
290 Event::Eof => break,
291 _ => {}
292 }
293 }
294
295 Ok(result.unwrap_or_else(|| TitleText::Rich(drawing::TextBody::new())))
296}
297
298fn parse_simple_string_reference(reader: &mut Reader) -> Result<(String, Option<String>)> {
302 let mut formula = String::new();
303 let mut cache = None;
304
305 loop {
306 match reader.read_event()? {
307 Event::Start(start) if start.local_name().as_ref() == b"f" => {
308 formula = read_text_content(reader, b"f")?;
309 }
310 Event::Start(start) if start.local_name().as_ref() == b"strCache" => {
311 cache = parse_string_data(reader)?
312 .points
313 .into_iter()
314 .next()
315 .map(|point| point.value);
316 }
317 Event::Start(_) => skip_subtree(reader)?,
318 Event::End(end) if end.local_name().as_ref() == b"strRef" => break,
319 Event::Eof => break,
320 _ => {}
321 }
322 }
323
324 Ok((formula, cache))
325}
326
327fn parse_series_title(reader: &mut Reader) -> Result<SeriesTitle> {
328 let mut result = None;
329
330 loop {
331 match reader.read_event()? {
332 Event::Start(start) if start.local_name().as_ref() == b"strRef" => {
333 let (formula, cache) = parse_simple_string_reference(reader)?;
334 result = Some(SeriesTitle::Reference { formula, cache });
335 }
336 Event::Start(start) if start.local_name().as_ref() == b"v" => {
337 result = Some(SeriesTitle::Literal(read_text_content(reader, b"v")?));
338 }
339 Event::Start(_) => skip_subtree(reader)?,
340 Event::End(end) if end.local_name().as_ref() == b"tx" => break,
341 Event::Eof => break,
342 _ => {}
343 }
344 }
345
346 Ok(result.unwrap_or_else(|| SeriesTitle::Literal(String::new())))
347}
348
349fn parse_legend(reader: &mut Reader) -> Result<Legend> {
350 let mut legend = Legend::new();
351
352 loop {
353 match reader.read_event()? {
354 Event::Empty(child) if child.local_name().as_ref() == b"legendPos" => {
355 legend.position =
356 raw_attribute(&child, b"val").and_then(|v| LegendPosition::from_xml_token(&v));
357 }
358 Event::Start(child) if child.local_name().as_ref() == b"legendPos" => {
359 legend.position =
360 raw_attribute(&child, b"val").and_then(|v| LegendPosition::from_xml_token(&v));
361 skip_subtree(reader)?;
362 }
363
364 Event::Empty(child) if child.local_name().as_ref() == b"overlay" => {
365 legend.overlay = parse_bool_val(&child);
366 }
367 Event::Start(child) if child.local_name().as_ref() == b"overlay" => {
368 legend.overlay = parse_bool_val(&child);
369 skip_subtree(reader)?;
370 }
371
372 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
373 legend.shape_properties = Some(drawing::read_shape_properties(reader)?);
374 }
375 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
376 legend.shape_properties = Some(drawing::ShapeProperties::new());
377 }
378
379 Event::Start(_) => skip_subtree(reader)?,
381 Event::Empty(_) => {}
382 Event::End(_) | Event::Eof => break,
383 _ => {}
384 }
385 }
386
387 Ok(legend)
388}
389
390fn parse_plot_area(reader: &mut Reader) -> Result<PlotArea> {
391 let mut plot_area = PlotArea::new();
392
393 loop {
394 match reader.read_event()? {
395 Event::Start(start) if start.local_name().as_ref() == b"barChart" => {
396 plot_area
397 .charts
398 .push(ChartType::Bar(parse_bar_chart(reader)?));
399 }
400 Event::Start(start) if start.local_name().as_ref() == b"lineChart" => {
401 plot_area
402 .charts
403 .push(ChartType::Line(parse_line_chart(reader)?));
404 }
405 Event::Start(start) if start.local_name().as_ref() == b"pieChart" => {
406 plot_area
407 .charts
408 .push(ChartType::Pie(parse_pie_chart(reader)?));
409 }
410 Event::Start(start) if start.local_name().as_ref() == b"doughnutChart" => {
411 plot_area
412 .charts
413 .push(ChartType::Doughnut(parse_doughnut_chart(reader)?));
414 }
415 Event::Start(start) if start.local_name().as_ref() == b"areaChart" => {
416 plot_area
417 .charts
418 .push(ChartType::Area(parse_area_chart(reader)?));
419 }
420 Event::Start(start) if start.local_name().as_ref() == b"scatterChart" => {
421 plot_area
422 .charts
423 .push(ChartType::Scatter(parse_scatter_chart(reader)?));
424 }
425 Event::Start(start) if start.local_name().as_ref() == b"bar3DChart" => {
426 plot_area
427 .charts
428 .push(ChartType::Bar3D(parse_bar3d_chart(reader)?));
429 }
430 Event::Start(start) if start.local_name().as_ref() == b"line3DChart" => {
431 plot_area
432 .charts
433 .push(ChartType::Line3D(parse_line3d_chart(reader)?));
434 }
435 Event::Start(start) if start.local_name().as_ref() == b"pie3DChart" => {
436 plot_area
437 .charts
438 .push(ChartType::Pie3D(parse_pie3d_chart(reader)?));
439 }
440 Event::Start(start) if start.local_name().as_ref() == b"area3DChart" => {
441 plot_area
442 .charts
443 .push(ChartType::Area3D(parse_area3d_chart(reader)?));
444 }
445 Event::Start(start) if start.local_name().as_ref() == b"surface3DChart" => {
446 plot_area
447 .charts
448 .push(ChartType::Surface3D(parse_surface3d_chart(reader)?));
449 }
450
451 Event::Start(start) if start.local_name().as_ref() == b"catAx" => {
452 plot_area
453 .axes
454 .push(Axis::Category(parse_category_axis(reader)?));
455 }
456 Event::Start(start) if start.local_name().as_ref() == b"valAx" => {
457 plot_area.axes.push(Axis::Value(parse_value_axis(reader)?));
458 }
459
460 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
461 plot_area.shape_properties = Some(drawing::read_shape_properties(reader)?);
462 }
463 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
464 plot_area.shape_properties = Some(drawing::ShapeProperties::new());
465 }
466
467 Event::Start(_) => skip_subtree(reader)?,
470 Event::Empty(_) => {}
471 Event::End(_) | Event::Eof => break,
472 _ => {}
473 }
474 }
475
476 Ok(plot_area)
477}
478
479fn parse_bar_chart(reader: &mut Reader) -> Result<BarChart> {
480 let mut direction = BarDirection::Column;
481 let mut grouping = None;
482 let mut vary_colors = None;
483 let mut series = Vec::new();
484 let mut gap_width_percent = None;
485 let mut overlap_percent = None;
486 let mut axis_ids: Vec<u32> = Vec::new();
487
488 loop {
489 match reader.read_event()? {
490 Event::Empty(child) if child.local_name().as_ref() == b"barDir" => {
491 direction = raw_attribute(&child, b"val")
492 .and_then(|v| BarDirection::from_xml_token(&v))
493 .unwrap_or(BarDirection::Column);
494 }
495 Event::Start(child) if child.local_name().as_ref() == b"barDir" => {
496 direction = raw_attribute(&child, b"val")
497 .and_then(|v| BarDirection::from_xml_token(&v))
498 .unwrap_or(BarDirection::Column);
499 skip_subtree(reader)?;
500 }
501
502 Event::Empty(child) if child.local_name().as_ref() == b"grouping" => {
503 grouping =
504 raw_attribute(&child, b"val").and_then(|v| BarGrouping::from_xml_token(&v));
505 }
506 Event::Start(child) if child.local_name().as_ref() == b"grouping" => {
507 grouping =
508 raw_attribute(&child, b"val").and_then(|v| BarGrouping::from_xml_token(&v));
509 skip_subtree(reader)?;
510 }
511
512 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
513 vary_colors = parse_bool_val(&child);
514 }
515 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
516 vary_colors = parse_bool_val(&child);
517 skip_subtree(reader)?;
518 }
519
520 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
521 series.push(parse_bar_series(reader)?);
522 }
523
524 Event::Empty(child) if child.local_name().as_ref() == b"gapWidth" => {
525 gap_width_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
526 }
527 Event::Start(child) if child.local_name().as_ref() == b"gapWidth" => {
528 gap_width_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
529 skip_subtree(reader)?;
530 }
531
532 Event::Empty(child) if child.local_name().as_ref() == b"overlap" => {
533 overlap_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
534 }
535 Event::Start(child) if child.local_name().as_ref() == b"overlap" => {
536 overlap_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
537 skip_subtree(reader)?;
538 }
539
540 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
541 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
542 axis_ids.push(id);
543 }
544 }
545 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
546 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
547 axis_ids.push(id);
548 }
549 skip_subtree(reader)?;
550 }
551
552 Event::Start(_) => skip_subtree(reader)?,
554 Event::Empty(_) => {}
555 Event::End(_) | Event::Eof => break,
556 _ => {}
557 }
558 }
559
560 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
561 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
562
563 let mut chart = BarChart::new(direction, category_axis_id, value_axis_id);
564 chart.grouping = grouping;
565 chart.vary_colors = vary_colors;
566 chart.series = series;
567 chart.gap_width_percent = gap_width_percent;
568 chart.overlap_percent = overlap_percent;
569 Ok(chart)
570}
571
572fn parse_line_chart(reader: &mut Reader) -> Result<LineChart> {
573 let mut grouping = LineGrouping::default();
574 let mut vary_colors = None;
575 let mut series = Vec::new();
576 let mut marker = None;
577 let mut smooth = None;
578 let mut axis_ids: Vec<u32> = Vec::new();
579
580 loop {
581 match reader.read_event()? {
582 Event::Empty(child) if child.local_name().as_ref() == b"grouping" => {
583 grouping = raw_attribute(&child, b"val")
584 .and_then(|v| LineGrouping::from_xml_token(&v))
585 .unwrap_or_default();
586 }
587 Event::Start(child) if child.local_name().as_ref() == b"grouping" => {
588 grouping = raw_attribute(&child, b"val")
589 .and_then(|v| LineGrouping::from_xml_token(&v))
590 .unwrap_or_default();
591 skip_subtree(reader)?;
592 }
593
594 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
595 vary_colors = parse_bool_val(&child);
596 }
597 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
598 vary_colors = parse_bool_val(&child);
599 skip_subtree(reader)?;
600 }
601
602 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
603 series.push(parse_line_series(reader)?);
604 }
605
606 Event::Empty(child) if child.local_name().as_ref() == b"marker" => {
607 marker = parse_bool_val(&child);
608 }
609 Event::Start(child) if child.local_name().as_ref() == b"marker" => {
610 marker = parse_bool_val(&child);
611 skip_subtree(reader)?;
612 }
613
614 Event::Empty(child) if child.local_name().as_ref() == b"smooth" => {
615 smooth = parse_bool_val(&child);
616 }
617 Event::Start(child) if child.local_name().as_ref() == b"smooth" => {
618 smooth = parse_bool_val(&child);
619 skip_subtree(reader)?;
620 }
621
622 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
623 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
624 axis_ids.push(id);
625 }
626 }
627 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
628 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
629 axis_ids.push(id);
630 }
631 skip_subtree(reader)?;
632 }
633
634 Event::Start(_) => skip_subtree(reader)?,
637 Event::Empty(_) => {}
638 Event::End(_) | Event::Eof => break,
639 _ => {}
640 }
641 }
642
643 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
644 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
645
646 let mut chart = LineChart::new(category_axis_id, value_axis_id);
647 chart.grouping = grouping;
648 chart.vary_colors = vary_colors;
649 chart.series = series;
650 chart.marker = marker;
651 chart.smooth = smooth;
652 Ok(chart)
653}
654
655fn parse_pie_chart(reader: &mut Reader) -> Result<PieChart> {
656 let mut chart = PieChart::new();
657
658 loop {
659 match reader.read_event()? {
660 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
661 chart.vary_colors = parse_bool_val(&child);
662 }
663 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
664 chart.vary_colors = parse_bool_val(&child);
665 skip_subtree(reader)?;
666 }
667
668 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
669 chart.series.push(parse_pie_series(reader)?);
670 }
671
672 Event::Empty(child) if child.local_name().as_ref() == b"firstSliceAng" => {
673 chart.first_slice_angle_degrees =
674 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
675 }
676 Event::Start(child) if child.local_name().as_ref() == b"firstSliceAng" => {
677 chart.first_slice_angle_degrees =
678 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
679 skip_subtree(reader)?;
680 }
681
682 Event::Start(_) => skip_subtree(reader)?,
684 Event::Empty(_) => {}
685 Event::End(_) | Event::Eof => break,
686 _ => {}
687 }
688 }
689
690 Ok(chart)
691}
692
693fn parse_bar_series(reader: &mut Reader) -> Result<BarSeries> {
694 let mut series = BarSeries::default();
695
696 loop {
697 match reader.read_event()? {
698 Event::Empty(child) if child.local_name().as_ref() == b"idx" => {
699 series.index = raw_attribute(&child, b"val")
700 .and_then(|v| v.parse().ok())
701 .unwrap_or(0);
702 }
703 Event::Start(child) if child.local_name().as_ref() == b"idx" => {
704 series.index = raw_attribute(&child, b"val")
705 .and_then(|v| v.parse().ok())
706 .unwrap_or(0);
707 skip_subtree(reader)?;
708 }
709
710 Event::Empty(child) if child.local_name().as_ref() == b"order" => {
711 series.order = raw_attribute(&child, b"val")
712 .and_then(|v| v.parse().ok())
713 .unwrap_or(0);
714 }
715 Event::Start(child) if child.local_name().as_ref() == b"order" => {
716 series.order = raw_attribute(&child, b"val")
717 .and_then(|v| v.parse().ok())
718 .unwrap_or(0);
719 skip_subtree(reader)?;
720 }
721
722 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
723 series.title = Some(parse_series_title(reader)?);
724 }
725
726 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
727 series.shape_properties = Some(drawing::read_shape_properties(reader)?);
728 }
729 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
730 series.shape_properties = Some(drawing::ShapeProperties::new());
731 }
732
733 Event::Start(start) if start.local_name().as_ref() == b"cat" => {
734 series.categories = parse_axis_data_source(reader)?;
735 }
736 Event::Start(start) if start.local_name().as_ref() == b"val" => {
737 series.values = parse_numeric_data_source(reader)?;
738 }
739
740 Event::Start(_) => skip_subtree(reader)?,
743 Event::Empty(_) => {}
744 Event::End(_) | Event::Eof => break,
745 _ => {}
746 }
747 }
748
749 Ok(series)
750}
751
752fn parse_line_series(reader: &mut Reader) -> Result<LineSeries> {
753 let mut series = LineSeries::default();
754
755 loop {
756 match reader.read_event()? {
757 Event::Empty(child) if child.local_name().as_ref() == b"idx" => {
758 series.index = raw_attribute(&child, b"val")
759 .and_then(|v| v.parse().ok())
760 .unwrap_or(0);
761 }
762 Event::Start(child) if child.local_name().as_ref() == b"idx" => {
763 series.index = raw_attribute(&child, b"val")
764 .and_then(|v| v.parse().ok())
765 .unwrap_or(0);
766 skip_subtree(reader)?;
767 }
768
769 Event::Empty(child) if child.local_name().as_ref() == b"order" => {
770 series.order = raw_attribute(&child, b"val")
771 .and_then(|v| v.parse().ok())
772 .unwrap_or(0);
773 }
774 Event::Start(child) if child.local_name().as_ref() == b"order" => {
775 series.order = raw_attribute(&child, b"val")
776 .and_then(|v| v.parse().ok())
777 .unwrap_or(0);
778 skip_subtree(reader)?;
779 }
780
781 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
782 series.title = Some(parse_series_title(reader)?);
783 }
784
785 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
786 series.shape_properties = Some(drawing::read_shape_properties(reader)?);
787 }
788 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
789 series.shape_properties = Some(drawing::ShapeProperties::new());
790 }
791
792 Event::Start(start) if start.local_name().as_ref() == b"marker" => {
793 series.marker = Some(parse_marker(reader, true)?);
794 }
795 Event::Empty(start) if start.local_name().as_ref() == b"marker" => {
796 series.marker = Some(parse_marker(reader, false)?);
797 }
798
799 Event::Start(start) if start.local_name().as_ref() == b"cat" => {
800 series.categories = parse_axis_data_source(reader)?;
801 }
802 Event::Start(start) if start.local_name().as_ref() == b"val" => {
803 series.values = parse_numeric_data_source(reader)?;
804 }
805
806 Event::Empty(child) if child.local_name().as_ref() == b"smooth" => {
807 series.smooth = parse_bool_val(&child);
808 }
809 Event::Start(child) if child.local_name().as_ref() == b"smooth" => {
810 series.smooth = parse_bool_val(&child);
811 skip_subtree(reader)?;
812 }
813
814 Event::Start(_) => skip_subtree(reader)?,
816 Event::Empty(_) => {}
817 Event::End(_) | Event::Eof => break,
818 _ => {}
819 }
820 }
821
822 Ok(series)
823}
824
825fn parse_pie_series(reader: &mut Reader) -> Result<PieSeries> {
826 let mut series = PieSeries::default();
827
828 loop {
829 match reader.read_event()? {
830 Event::Empty(child) if child.local_name().as_ref() == b"idx" => {
831 series.index = raw_attribute(&child, b"val")
832 .and_then(|v| v.parse().ok())
833 .unwrap_or(0);
834 }
835 Event::Start(child) if child.local_name().as_ref() == b"idx" => {
836 series.index = raw_attribute(&child, b"val")
837 .and_then(|v| v.parse().ok())
838 .unwrap_or(0);
839 skip_subtree(reader)?;
840 }
841
842 Event::Empty(child) if child.local_name().as_ref() == b"order" => {
843 series.order = raw_attribute(&child, b"val")
844 .and_then(|v| v.parse().ok())
845 .unwrap_or(0);
846 }
847 Event::Start(child) if child.local_name().as_ref() == b"order" => {
848 series.order = raw_attribute(&child, b"val")
849 .and_then(|v| v.parse().ok())
850 .unwrap_or(0);
851 skip_subtree(reader)?;
852 }
853
854 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
855 series.title = Some(parse_series_title(reader)?);
856 }
857
858 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
859 series.shape_properties = Some(drawing::read_shape_properties(reader)?);
860 }
861 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
862 series.shape_properties = Some(drawing::ShapeProperties::new());
863 }
864
865 Event::Start(start) if start.local_name().as_ref() == b"cat" => {
866 series.categories = parse_axis_data_source(reader)?;
867 }
868 Event::Start(start) if start.local_name().as_ref() == b"val" => {
869 series.values = parse_numeric_data_source(reader)?;
870 }
871
872 Event::Start(_) => skip_subtree(reader)?,
874 Event::Empty(_) => {}
875 Event::End(_) | Event::Eof => break,
876 _ => {}
877 }
878 }
879
880 Ok(series)
881}
882
883fn parse_doughnut_chart(reader: &mut Reader) -> Result<DoughnutChart> {
889 let mut chart = DoughnutChart::new();
890
891 loop {
892 match reader.read_event()? {
893 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
894 chart.vary_colors = parse_bool_val(&child);
895 }
896 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
897 chart.vary_colors = parse_bool_val(&child);
898 skip_subtree(reader)?;
899 }
900
901 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
902 chart.series.push(parse_pie_series(reader)?);
903 }
904
905 Event::Empty(child) if child.local_name().as_ref() == b"firstSliceAng" => {
906 chart.first_slice_angle_degrees =
907 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
908 }
909 Event::Start(child) if child.local_name().as_ref() == b"firstSliceAng" => {
910 chart.first_slice_angle_degrees =
911 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
912 skip_subtree(reader)?;
913 }
914
915 Event::Empty(child) if child.local_name().as_ref() == b"holeSize" => {
916 chart.hole_size_percent = raw_attribute(&child, b"val")
917 .and_then(|v| parse_percent(&v))
918 .and_then(|v| u8::try_from(v).ok());
919 }
920 Event::Start(child) if child.local_name().as_ref() == b"holeSize" => {
921 chart.hole_size_percent = raw_attribute(&child, b"val")
922 .and_then(|v| parse_percent(&v))
923 .and_then(|v| u8::try_from(v).ok());
924 skip_subtree(reader)?;
925 }
926
927 Event::Start(_) => skip_subtree(reader)?,
929 Event::Empty(_) => {}
930 Event::End(_) | Event::Eof => break,
931 _ => {}
932 }
933 }
934
935 Ok(chart)
936}
937
938fn parse_area_chart(reader: &mut Reader) -> Result<AreaChart> {
939 let mut grouping = None;
940 let mut vary_colors = None;
941 let mut series = Vec::new();
942 let mut axis_ids: Vec<u32> = Vec::new();
943
944 loop {
945 match reader.read_event()? {
946 Event::Empty(child) if child.local_name().as_ref() == b"grouping" => {
947 grouping =
948 raw_attribute(&child, b"val").and_then(|v| LineGrouping::from_xml_token(&v));
949 }
950 Event::Start(child) if child.local_name().as_ref() == b"grouping" => {
951 grouping =
952 raw_attribute(&child, b"val").and_then(|v| LineGrouping::from_xml_token(&v));
953 skip_subtree(reader)?;
954 }
955
956 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
957 vary_colors = parse_bool_val(&child);
958 }
959 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
960 vary_colors = parse_bool_val(&child);
961 skip_subtree(reader)?;
962 }
963
964 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
965 series.push(parse_area_series(reader)?);
966 }
967
968 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
969 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
970 axis_ids.push(id);
971 }
972 }
973 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
974 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
975 axis_ids.push(id);
976 }
977 skip_subtree(reader)?;
978 }
979
980 Event::Start(_) => skip_subtree(reader)?,
982 Event::Empty(_) => {}
983 Event::End(_) | Event::Eof => break,
984 _ => {}
985 }
986 }
987
988 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
989 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
990
991 let mut chart = AreaChart::new(category_axis_id, value_axis_id);
992 chart.grouping = grouping;
993 chart.vary_colors = vary_colors;
994 chart.series = series;
995 Ok(chart)
996}
997
998fn parse_area_series(reader: &mut Reader) -> Result<AreaSeries> {
999 let mut series = AreaSeries::default();
1000
1001 loop {
1002 match reader.read_event()? {
1003 Event::Empty(child) if child.local_name().as_ref() == b"idx" => {
1004 series.index = raw_attribute(&child, b"val")
1005 .and_then(|v| v.parse().ok())
1006 .unwrap_or(0);
1007 }
1008 Event::Start(child) if child.local_name().as_ref() == b"idx" => {
1009 series.index = raw_attribute(&child, b"val")
1010 .and_then(|v| v.parse().ok())
1011 .unwrap_or(0);
1012 skip_subtree(reader)?;
1013 }
1014
1015 Event::Empty(child) if child.local_name().as_ref() == b"order" => {
1016 series.order = raw_attribute(&child, b"val")
1017 .and_then(|v| v.parse().ok())
1018 .unwrap_or(0);
1019 }
1020 Event::Start(child) if child.local_name().as_ref() == b"order" => {
1021 series.order = raw_attribute(&child, b"val")
1022 .and_then(|v| v.parse().ok())
1023 .unwrap_or(0);
1024 skip_subtree(reader)?;
1025 }
1026
1027 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
1028 series.title = Some(parse_series_title(reader)?);
1029 }
1030
1031 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
1032 series.shape_properties = Some(drawing::read_shape_properties(reader)?);
1033 }
1034 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
1035 series.shape_properties = Some(drawing::ShapeProperties::new());
1036 }
1037
1038 Event::Start(start) if start.local_name().as_ref() == b"cat" => {
1039 series.categories = parse_axis_data_source(reader)?;
1040 }
1041 Event::Start(start) if start.local_name().as_ref() == b"val" => {
1042 series.values = parse_numeric_data_source(reader)?;
1043 }
1044
1045 Event::Start(_) => skip_subtree(reader)?,
1047 Event::Empty(_) => {}
1048 Event::End(_) | Event::Eof => break,
1049 _ => {}
1050 }
1051 }
1052
1053 Ok(series)
1054}
1055
1056fn parse_scatter_chart(reader: &mut Reader) -> Result<ScatterChart> {
1057 let mut style = ScatterStyle::default();
1058 let mut vary_colors = None;
1059 let mut series = Vec::new();
1060 let mut axis_ids: Vec<u32> = Vec::new();
1061
1062 loop {
1063 match reader.read_event()? {
1064 Event::Empty(child) if child.local_name().as_ref() == b"scatterStyle" => {
1065 style = raw_attribute(&child, b"val")
1066 .and_then(|v| ScatterStyle::from_xml_token(&v))
1067 .unwrap_or_default();
1068 }
1069 Event::Start(child) if child.local_name().as_ref() == b"scatterStyle" => {
1070 style = raw_attribute(&child, b"val")
1071 .and_then(|v| ScatterStyle::from_xml_token(&v))
1072 .unwrap_or_default();
1073 skip_subtree(reader)?;
1074 }
1075
1076 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
1077 vary_colors = parse_bool_val(&child);
1078 }
1079 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
1080 vary_colors = parse_bool_val(&child);
1081 skip_subtree(reader)?;
1082 }
1083
1084 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
1085 series.push(parse_scatter_series(reader)?);
1086 }
1087
1088 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1089 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1090 axis_ids.push(id);
1091 }
1092 }
1093 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1094 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1095 axis_ids.push(id);
1096 }
1097 skip_subtree(reader)?;
1098 }
1099
1100 Event::Start(_) => skip_subtree(reader)?,
1102 Event::Empty(_) => {}
1103 Event::End(_) | Event::Eof => break,
1104 _ => {}
1105 }
1106 }
1107
1108 let x_axis_id = axis_ids.first().copied().unwrap_or(0);
1109 let y_axis_id = axis_ids.get(1).copied().unwrap_or(0);
1110
1111 let mut chart = ScatterChart::new(x_axis_id, y_axis_id);
1112 chart.style = style;
1113 chart.vary_colors = vary_colors;
1114 chart.series = series;
1115 Ok(chart)
1116}
1117
1118fn parse_scatter_series(reader: &mut Reader) -> Result<ScatterSeries> {
1119 let mut series = ScatterSeries::default();
1120
1121 loop {
1122 match reader.read_event()? {
1123 Event::Empty(child) if child.local_name().as_ref() == b"idx" => {
1124 series.index = raw_attribute(&child, b"val")
1125 .and_then(|v| v.parse().ok())
1126 .unwrap_or(0);
1127 }
1128 Event::Start(child) if child.local_name().as_ref() == b"idx" => {
1129 series.index = raw_attribute(&child, b"val")
1130 .and_then(|v| v.parse().ok())
1131 .unwrap_or(0);
1132 skip_subtree(reader)?;
1133 }
1134
1135 Event::Empty(child) if child.local_name().as_ref() == b"order" => {
1136 series.order = raw_attribute(&child, b"val")
1137 .and_then(|v| v.parse().ok())
1138 .unwrap_or(0);
1139 }
1140 Event::Start(child) if child.local_name().as_ref() == b"order" => {
1141 series.order = raw_attribute(&child, b"val")
1142 .and_then(|v| v.parse().ok())
1143 .unwrap_or(0);
1144 skip_subtree(reader)?;
1145 }
1146
1147 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
1148 series.title = Some(parse_series_title(reader)?);
1149 }
1150
1151 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
1152 series.shape_properties = Some(drawing::read_shape_properties(reader)?);
1153 }
1154 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
1155 series.shape_properties = Some(drawing::ShapeProperties::new());
1156 }
1157
1158 Event::Start(start) if start.local_name().as_ref() == b"marker" => {
1159 series.marker = Some(parse_marker(reader, true)?);
1160 }
1161 Event::Empty(start) if start.local_name().as_ref() == b"marker" => {
1162 series.marker = Some(parse_marker(reader, false)?);
1163 }
1164
1165 Event::Start(start) if start.local_name().as_ref() == b"xVal" => {
1166 series.x_values = parse_axis_data_source(reader)?;
1167 }
1168 Event::Start(start) if start.local_name().as_ref() == b"yVal" => {
1169 series.y_values = parse_numeric_data_source(reader)?;
1170 }
1171
1172 Event::Empty(child) if child.local_name().as_ref() == b"smooth" => {
1173 series.smooth = parse_bool_val(&child);
1174 }
1175 Event::Start(child) if child.local_name().as_ref() == b"smooth" => {
1176 series.smooth = parse_bool_val(&child);
1177 skip_subtree(reader)?;
1178 }
1179
1180 Event::Start(_) => skip_subtree(reader)?,
1182 Event::Empty(_) => {}
1183 Event::End(_) | Event::Eof => break,
1184 _ => {}
1185 }
1186 }
1187
1188 Ok(series)
1189}
1190
1191fn parse_view_3d(reader: &mut Reader) -> Result<View3D> {
1196 let mut view = View3D::new();
1197
1198 loop {
1199 match reader.read_event()? {
1200 Event::Empty(child) if child.local_name().as_ref() == b"rotX" => {
1201 view.rotation_x_degrees =
1202 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1203 }
1204 Event::Start(child) if child.local_name().as_ref() == b"rotX" => {
1205 view.rotation_x_degrees =
1206 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1207 skip_subtree(reader)?;
1208 }
1209
1210 Event::Empty(child) if child.local_name().as_ref() == b"hPercent" => {
1211 view.height_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1212 }
1213 Event::Start(child) if child.local_name().as_ref() == b"hPercent" => {
1214 view.height_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1215 skip_subtree(reader)?;
1216 }
1217
1218 Event::Empty(child) if child.local_name().as_ref() == b"rotY" => {
1219 view.rotation_y_degrees =
1220 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1221 }
1222 Event::Start(child) if child.local_name().as_ref() == b"rotY" => {
1223 view.rotation_y_degrees =
1224 raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1225 skip_subtree(reader)?;
1226 }
1227
1228 Event::Empty(child) if child.local_name().as_ref() == b"depthPercent" => {
1229 view.depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1230 }
1231 Event::Start(child) if child.local_name().as_ref() == b"depthPercent" => {
1232 view.depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1233 skip_subtree(reader)?;
1234 }
1235
1236 Event::Empty(child) if child.local_name().as_ref() == b"rAngAx" => {
1237 view.right_angle_axes = parse_bool_val(&child);
1238 }
1239 Event::Start(child) if child.local_name().as_ref() == b"rAngAx" => {
1240 view.right_angle_axes = parse_bool_val(&child);
1241 skip_subtree(reader)?;
1242 }
1243
1244 Event::Empty(child) if child.local_name().as_ref() == b"perspective" => {
1245 view.perspective = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1246 }
1247 Event::Start(child) if child.local_name().as_ref() == b"perspective" => {
1248 view.perspective = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1249 skip_subtree(reader)?;
1250 }
1251
1252 Event::Start(_) => skip_subtree(reader)?,
1254 Event::Empty(_) => {}
1255 Event::End(_) | Event::Eof => break,
1256 _ => {}
1257 }
1258 }
1259
1260 Ok(view)
1261}
1262
1263fn parse_surface(reader: &mut Reader) -> Result<Surface> {
1264 let mut surface = Surface::new();
1265
1266 loop {
1267 match reader.read_event()? {
1268 Event::Empty(child) if child.local_name().as_ref() == b"thickness" => {
1269 surface.thickness_percent =
1270 raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1271 }
1272 Event::Start(child) if child.local_name().as_ref() == b"thickness" => {
1273 surface.thickness_percent =
1274 raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1275 skip_subtree(reader)?;
1276 }
1277
1278 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
1279 surface.shape_properties = Some(drawing::read_shape_properties(reader)?);
1280 }
1281 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
1282 surface.shape_properties = Some(drawing::ShapeProperties::new());
1283 }
1284
1285 Event::Start(_) => skip_subtree(reader)?,
1287 Event::Empty(_) => {}
1288 Event::End(_) | Event::Eof => break,
1289 _ => {}
1290 }
1291 }
1292
1293 Ok(surface)
1294}
1295
1296fn parse_bar3d_chart(reader: &mut Reader) -> Result<Bar3DChart> {
1297 let mut direction = BarDirection::Column;
1298 let mut grouping = None;
1299 let mut vary_colors = None;
1300 let mut series = Vec::new();
1301 let mut gap_width_percent = None;
1302 let mut gap_depth_percent = None;
1303 let mut shape = None;
1304 let mut axis_ids: Vec<u32> = Vec::new();
1305
1306 loop {
1307 match reader.read_event()? {
1308 Event::Empty(child) if child.local_name().as_ref() == b"barDir" => {
1309 direction = raw_attribute(&child, b"val")
1310 .and_then(|v| BarDirection::from_xml_token(&v))
1311 .unwrap_or(BarDirection::Column);
1312 }
1313 Event::Start(child) if child.local_name().as_ref() == b"barDir" => {
1314 direction = raw_attribute(&child, b"val")
1315 .and_then(|v| BarDirection::from_xml_token(&v))
1316 .unwrap_or(BarDirection::Column);
1317 skip_subtree(reader)?;
1318 }
1319
1320 Event::Empty(child) if child.local_name().as_ref() == b"grouping" => {
1321 grouping =
1322 raw_attribute(&child, b"val").and_then(|v| BarGrouping::from_xml_token(&v));
1323 }
1324 Event::Start(child) if child.local_name().as_ref() == b"grouping" => {
1325 grouping =
1326 raw_attribute(&child, b"val").and_then(|v| BarGrouping::from_xml_token(&v));
1327 skip_subtree(reader)?;
1328 }
1329
1330 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
1331 vary_colors = parse_bool_val(&child);
1332 }
1333 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
1334 vary_colors = parse_bool_val(&child);
1335 skip_subtree(reader)?;
1336 }
1337
1338 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
1339 series.push(parse_bar_series(reader)?);
1340 }
1341
1342 Event::Empty(child) if child.local_name().as_ref() == b"gapWidth" => {
1343 gap_width_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1344 }
1345 Event::Start(child) if child.local_name().as_ref() == b"gapWidth" => {
1346 gap_width_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1347 skip_subtree(reader)?;
1348 }
1349
1350 Event::Empty(child) if child.local_name().as_ref() == b"gapDepth" => {
1351 gap_depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1352 }
1353 Event::Start(child) if child.local_name().as_ref() == b"gapDepth" => {
1354 gap_depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1355 skip_subtree(reader)?;
1356 }
1357
1358 Event::Empty(child) if child.local_name().as_ref() == b"shape" => {
1359 shape = raw_attribute(&child, b"val").and_then(|v| Bar3DShape::from_xml_token(&v));
1360 }
1361 Event::Start(child) if child.local_name().as_ref() == b"shape" => {
1362 shape = raw_attribute(&child, b"val").and_then(|v| Bar3DShape::from_xml_token(&v));
1363 skip_subtree(reader)?;
1364 }
1365
1366 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1367 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1368 axis_ids.push(id);
1369 }
1370 }
1371 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1372 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1373 axis_ids.push(id);
1374 }
1375 skip_subtree(reader)?;
1376 }
1377
1378 Event::Start(_) => skip_subtree(reader)?,
1380 Event::Empty(_) => {}
1381 Event::End(_) | Event::Eof => break,
1382 _ => {}
1383 }
1384 }
1385
1386 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
1387 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
1388 let series_axis_id = axis_ids.get(2).copied();
1389
1390 let mut chart = Bar3DChart::new(direction, category_axis_id, value_axis_id);
1391 chart.grouping = grouping;
1392 chart.vary_colors = vary_colors;
1393 chart.series = series;
1394 chart.gap_width_percent = gap_width_percent;
1395 chart.gap_depth_percent = gap_depth_percent;
1396 chart.shape = shape;
1397 chart.series_axis_id = series_axis_id;
1398 Ok(chart)
1399}
1400
1401fn parse_line3d_chart(reader: &mut Reader) -> Result<Line3DChart> {
1402 let mut grouping = LineGrouping::default();
1403 let mut vary_colors = None;
1404 let mut series = Vec::new();
1405 let mut gap_depth_percent = None;
1406 let mut axis_ids: Vec<u32> = Vec::new();
1407
1408 loop {
1409 match reader.read_event()? {
1410 Event::Empty(child) if child.local_name().as_ref() == b"grouping" => {
1411 grouping = raw_attribute(&child, b"val")
1412 .and_then(|v| LineGrouping::from_xml_token(&v))
1413 .unwrap_or_default();
1414 }
1415 Event::Start(child) if child.local_name().as_ref() == b"grouping" => {
1416 grouping = raw_attribute(&child, b"val")
1417 .and_then(|v| LineGrouping::from_xml_token(&v))
1418 .unwrap_or_default();
1419 skip_subtree(reader)?;
1420 }
1421
1422 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
1423 vary_colors = parse_bool_val(&child);
1424 }
1425 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
1426 vary_colors = parse_bool_val(&child);
1427 skip_subtree(reader)?;
1428 }
1429
1430 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
1431 series.push(parse_line_series(reader)?);
1432 }
1433
1434 Event::Empty(child) if child.local_name().as_ref() == b"gapDepth" => {
1435 gap_depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1436 }
1437 Event::Start(child) if child.local_name().as_ref() == b"gapDepth" => {
1438 gap_depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1439 skip_subtree(reader)?;
1440 }
1441
1442 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1443 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1444 axis_ids.push(id);
1445 }
1446 }
1447 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1448 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1449 axis_ids.push(id);
1450 }
1451 skip_subtree(reader)?;
1452 }
1453
1454 Event::Start(_) => skip_subtree(reader)?,
1456 Event::Empty(_) => {}
1457 Event::End(_) | Event::Eof => break,
1458 _ => {}
1459 }
1460 }
1461
1462 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
1463 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
1464 let series_axis_id = axis_ids.get(2).copied().unwrap_or(0);
1465
1466 let mut chart = Line3DChart::new(category_axis_id, value_axis_id, series_axis_id);
1467 chart.grouping = grouping;
1468 chart.vary_colors = vary_colors;
1469 chart.series = series;
1470 chart.gap_depth_percent = gap_depth_percent;
1471 Ok(chart)
1472}
1473
1474fn parse_pie3d_chart(reader: &mut Reader) -> Result<Pie3DChart> {
1475 let mut chart = Pie3DChart::new();
1476
1477 loop {
1478 match reader.read_event()? {
1479 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
1480 chart.vary_colors = parse_bool_val(&child);
1481 }
1482 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
1483 chart.vary_colors = parse_bool_val(&child);
1484 skip_subtree(reader)?;
1485 }
1486
1487 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
1488 chart.series.push(parse_pie_series(reader)?);
1489 }
1490
1491 Event::Start(_) => skip_subtree(reader)?,
1493 Event::Empty(_) => {}
1494 Event::End(_) | Event::Eof => break,
1495 _ => {}
1496 }
1497 }
1498
1499 Ok(chart)
1500}
1501
1502fn parse_area3d_chart(reader: &mut Reader) -> Result<Area3DChart> {
1503 let mut grouping = None;
1504 let mut vary_colors = None;
1505 let mut series = Vec::new();
1506 let mut gap_depth_percent = None;
1507 let mut axis_ids: Vec<u32> = Vec::new();
1508
1509 loop {
1510 match reader.read_event()? {
1511 Event::Empty(child) if child.local_name().as_ref() == b"grouping" => {
1512 grouping =
1513 raw_attribute(&child, b"val").and_then(|v| LineGrouping::from_xml_token(&v));
1514 }
1515 Event::Start(child) if child.local_name().as_ref() == b"grouping" => {
1516 grouping =
1517 raw_attribute(&child, b"val").and_then(|v| LineGrouping::from_xml_token(&v));
1518 skip_subtree(reader)?;
1519 }
1520
1521 Event::Empty(child) if child.local_name().as_ref() == b"varyColors" => {
1522 vary_colors = parse_bool_val(&child);
1523 }
1524 Event::Start(child) if child.local_name().as_ref() == b"varyColors" => {
1525 vary_colors = parse_bool_val(&child);
1526 skip_subtree(reader)?;
1527 }
1528
1529 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
1530 series.push(parse_area_series(reader)?);
1531 }
1532
1533 Event::Empty(child) if child.local_name().as_ref() == b"gapDepth" => {
1534 gap_depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1535 }
1536 Event::Start(child) if child.local_name().as_ref() == b"gapDepth" => {
1537 gap_depth_percent = raw_attribute(&child, b"val").and_then(|v| parse_percent(&v));
1538 skip_subtree(reader)?;
1539 }
1540
1541 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1542 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1543 axis_ids.push(id);
1544 }
1545 }
1546 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1547 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1548 axis_ids.push(id);
1549 }
1550 skip_subtree(reader)?;
1551 }
1552
1553 Event::Start(_) => skip_subtree(reader)?,
1555 Event::Empty(_) => {}
1556 Event::End(_) | Event::Eof => break,
1557 _ => {}
1558 }
1559 }
1560
1561 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
1562 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
1563 let series_axis_id = axis_ids.get(2).copied();
1564
1565 let mut chart = Area3DChart::new(category_axis_id, value_axis_id);
1566 chart.grouping = grouping;
1567 chart.vary_colors = vary_colors;
1568 chart.series = series;
1569 chart.gap_depth_percent = gap_depth_percent;
1570 chart.series_axis_id = series_axis_id;
1571 Ok(chart)
1572}
1573
1574fn parse_surface_series(reader: &mut Reader) -> Result<SurfaceSeries> {
1575 let mut series = SurfaceSeries::default();
1576
1577 loop {
1578 match reader.read_event()? {
1579 Event::Empty(child) if child.local_name().as_ref() == b"idx" => {
1580 series.index = raw_attribute(&child, b"val")
1581 .and_then(|v| v.parse().ok())
1582 .unwrap_or(0);
1583 }
1584 Event::Start(child) if child.local_name().as_ref() == b"idx" => {
1585 series.index = raw_attribute(&child, b"val")
1586 .and_then(|v| v.parse().ok())
1587 .unwrap_or(0);
1588 skip_subtree(reader)?;
1589 }
1590
1591 Event::Empty(child) if child.local_name().as_ref() == b"order" => {
1592 series.order = raw_attribute(&child, b"val")
1593 .and_then(|v| v.parse().ok())
1594 .unwrap_or(0);
1595 }
1596 Event::Start(child) if child.local_name().as_ref() == b"order" => {
1597 series.order = raw_attribute(&child, b"val")
1598 .and_then(|v| v.parse().ok())
1599 .unwrap_or(0);
1600 skip_subtree(reader)?;
1601 }
1602
1603 Event::Start(start) if start.local_name().as_ref() == b"tx" => {
1604 series.title = Some(parse_series_title(reader)?);
1605 }
1606
1607 Event::Start(start) if start.local_name().as_ref() == b"cat" => {
1608 series.categories = parse_axis_data_source(reader)?;
1609 }
1610 Event::Start(start) if start.local_name().as_ref() == b"val" => {
1611 series.values = parse_numeric_data_source(reader)?;
1612 }
1613
1614 Event::Start(_) => skip_subtree(reader)?,
1616 Event::Empty(_) => {}
1617 Event::End(_) | Event::Eof => break,
1618 _ => {}
1619 }
1620 }
1621
1622 Ok(series)
1623}
1624
1625fn parse_surface3d_chart(reader: &mut Reader) -> Result<Surface3DChart> {
1626 let mut wireframe = None;
1627 let mut series = Vec::new();
1628 let mut axis_ids: Vec<u32> = Vec::new();
1629
1630 loop {
1631 match reader.read_event()? {
1632 Event::Empty(child) if child.local_name().as_ref() == b"wireframe" => {
1633 wireframe = parse_bool_val(&child);
1634 }
1635 Event::Start(child) if child.local_name().as_ref() == b"wireframe" => {
1636 wireframe = parse_bool_val(&child);
1637 skip_subtree(reader)?;
1638 }
1639
1640 Event::Start(start) if start.local_name().as_ref() == b"ser" => {
1641 series.push(parse_surface_series(reader)?);
1642 }
1643
1644 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1645 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1646 axis_ids.push(id);
1647 }
1648 }
1649 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1650 if let Some(id) = raw_attribute(&child, b"val").and_then(|v| v.parse().ok()) {
1651 axis_ids.push(id);
1652 }
1653 skip_subtree(reader)?;
1654 }
1655
1656 Event::Start(_) => skip_subtree(reader)?,
1658 Event::Empty(_) => {}
1659 Event::End(_) | Event::Eof => break,
1660 _ => {}
1661 }
1662 }
1663
1664 let category_axis_id = axis_ids.first().copied().unwrap_or(0);
1665 let value_axis_id = axis_ids.get(1).copied().unwrap_or(0);
1666 let series_axis_id = axis_ids.get(2).copied().unwrap_or(0);
1667
1668 let mut chart = Surface3DChart::new(category_axis_id, value_axis_id, series_axis_id);
1669 chart.wireframe = wireframe;
1670 chart.series = series;
1671 Ok(chart)
1672}
1673
1674fn parse_marker(reader: &mut Reader, is_start: bool) -> Result<Marker> {
1675 let mut marker = Marker::new();
1676
1677 if !is_start {
1678 return Ok(marker);
1679 }
1680
1681 loop {
1682 match reader.read_event()? {
1683 Event::Empty(child) if child.local_name().as_ref() == b"symbol" => {
1684 marker.symbol =
1685 raw_attribute(&child, b"val").and_then(|v| MarkerSymbol::from_xml_token(&v));
1686 }
1687 Event::Start(child) if child.local_name().as_ref() == b"symbol" => {
1688 marker.symbol =
1689 raw_attribute(&child, b"val").and_then(|v| MarkerSymbol::from_xml_token(&v));
1690 skip_subtree(reader)?;
1691 }
1692
1693 Event::Empty(child) if child.local_name().as_ref() == b"size" => {
1694 marker.size = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1695 }
1696 Event::Start(child) if child.local_name().as_ref() == b"size" => {
1697 marker.size = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1698 skip_subtree(reader)?;
1699 }
1700
1701 Event::Start(start) if start.local_name().as_ref() == b"spPr" => {
1702 marker.shape_properties = Some(drawing::read_shape_properties(reader)?);
1703 }
1704 Event::Empty(start) if start.local_name().as_ref() == b"spPr" => {
1705 marker.shape_properties = Some(drawing::ShapeProperties::new());
1706 }
1707
1708 Event::Start(_) => skip_subtree(reader)?,
1709 Event::Empty(_) => {}
1710 Event::End(_) | Event::Eof => break,
1711 _ => {}
1712 }
1713 }
1714
1715 Ok(marker)
1716}
1717
1718struct AxisScaling {
1722 log_base: Option<f64>,
1723 reversed: bool,
1724 max: Option<f64>,
1725 min: Option<f64>,
1726}
1727
1728fn parse_scaling(reader: &mut Reader) -> Result<AxisScaling> {
1729 let mut log_base = None;
1730 let mut reversed = false;
1731 let mut max = None;
1732 let mut min = None;
1733
1734 loop {
1735 match reader.read_event()? {
1736 Event::Empty(child) if child.local_name().as_ref() == b"logBase" => {
1737 log_base = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1738 }
1739 Event::Start(child) if child.local_name().as_ref() == b"logBase" => {
1740 log_base = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1741 skip_subtree(reader)?;
1742 }
1743
1744 Event::Empty(child) if child.local_name().as_ref() == b"orientation" => {
1745 reversed = raw_attribute(&child, b"val").as_deref() == Some("maxMin");
1746 }
1747 Event::Start(child) if child.local_name().as_ref() == b"orientation" => {
1748 reversed = raw_attribute(&child, b"val").as_deref() == Some("maxMin");
1749 skip_subtree(reader)?;
1750 }
1751
1752 Event::Empty(child) if child.local_name().as_ref() == b"max" => {
1753 max = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1754 }
1755 Event::Start(child) if child.local_name().as_ref() == b"max" => {
1756 max = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1757 skip_subtree(reader)?;
1758 }
1759
1760 Event::Empty(child) if child.local_name().as_ref() == b"min" => {
1761 min = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1762 }
1763 Event::Start(child) if child.local_name().as_ref() == b"min" => {
1764 min = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
1765 skip_subtree(reader)?;
1766 }
1767
1768 Event::Start(_) => skip_subtree(reader)?,
1769 Event::Empty(_) => {}
1770 Event::End(_) | Event::Eof => break,
1771 _ => {}
1772 }
1773 }
1774
1775 Ok(AxisScaling {
1776 log_base,
1777 reversed,
1778 max,
1779 min,
1780 })
1781}
1782
1783fn parse_category_axis(reader: &mut Reader) -> Result<CategoryAxis> {
1784 let mut id = 0u32;
1785 let mut position = AxisPosition::Bottom;
1786 let mut cross_axis_id = 0u32;
1787 let mut log_base = None;
1788 let mut min = None;
1789 let mut max = None;
1790 let mut reversed = false;
1791 let mut major_gridlines = false;
1792 let mut minor_gridlines = false;
1793 let mut title = None;
1794
1795 loop {
1796 match reader.read_event()? {
1797 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1798 id = raw_attribute(&child, b"val")
1799 .and_then(|v| v.parse().ok())
1800 .unwrap_or(0);
1801 }
1802 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1803 id = raw_attribute(&child, b"val")
1804 .and_then(|v| v.parse().ok())
1805 .unwrap_or(0);
1806 skip_subtree(reader)?;
1807 }
1808
1809 Event::Start(start) if start.local_name().as_ref() == b"scaling" => {
1810 let scaling = parse_scaling(reader)?;
1811 log_base = scaling.log_base;
1812 reversed = scaling.reversed;
1813 max = scaling.max;
1814 min = scaling.min;
1815 }
1816
1817 Event::Empty(child) if child.local_name().as_ref() == b"axPos" => {
1818 position = raw_attribute(&child, b"val")
1819 .and_then(|v| AxisPosition::from_xml_token(&v))
1820 .unwrap_or(AxisPosition::Bottom);
1821 }
1822 Event::Start(child) if child.local_name().as_ref() == b"axPos" => {
1823 position = raw_attribute(&child, b"val")
1824 .and_then(|v| AxisPosition::from_xml_token(&v))
1825 .unwrap_or(AxisPosition::Bottom);
1826 skip_subtree(reader)?;
1827 }
1828
1829 Event::Empty(child) if child.local_name().as_ref() == b"majorGridlines" => {
1830 major_gridlines = true;
1831 }
1832 Event::Start(child) if child.local_name().as_ref() == b"majorGridlines" => {
1833 major_gridlines = true;
1834 skip_subtree(reader)?;
1835 }
1836
1837 Event::Empty(child) if child.local_name().as_ref() == b"minorGridlines" => {
1838 minor_gridlines = true;
1839 }
1840 Event::Start(child) if child.local_name().as_ref() == b"minorGridlines" => {
1841 minor_gridlines = true;
1842 skip_subtree(reader)?;
1843 }
1844
1845 Event::Start(start) if start.local_name().as_ref() == b"title" => {
1846 title = Some(parse_title(reader)?);
1847 }
1848 Event::Empty(start) if start.local_name().as_ref() == b"title" => {
1849 title = Some(Title::new());
1850 }
1851
1852 Event::Empty(child) if child.local_name().as_ref() == b"crossAx" => {
1853 cross_axis_id = raw_attribute(&child, b"val")
1854 .and_then(|v| v.parse().ok())
1855 .unwrap_or(0);
1856 }
1857 Event::Start(child) if child.local_name().as_ref() == b"crossAx" => {
1858 cross_axis_id = raw_attribute(&child, b"val")
1859 .and_then(|v| v.parse().ok())
1860 .unwrap_or(0);
1861 skip_subtree(reader)?;
1862 }
1863
1864 Event::Start(_) => skip_subtree(reader)?,
1869 Event::Empty(_) => {}
1870 Event::End(_) | Event::Eof => break,
1871 _ => {}
1872 }
1873 }
1874
1875 let mut axis = CategoryAxis::new(id, position, cross_axis_id);
1876 axis.log_base = log_base;
1877 axis.min = min;
1878 axis.max = max;
1879 axis.reversed = reversed;
1880 axis.major_gridlines = major_gridlines;
1881 axis.minor_gridlines = minor_gridlines;
1882 axis.title = title;
1883 Ok(axis)
1884}
1885
1886fn parse_value_axis(reader: &mut Reader) -> Result<ValueAxis> {
1887 let mut id = 0u32;
1888 let mut position = AxisPosition::Left;
1889 let mut cross_axis_id = 0u32;
1890 let mut log_base = None;
1891 let mut min = None;
1892 let mut max = None;
1893 let mut reversed = false;
1894 let mut major_gridlines = false;
1895 let mut minor_gridlines = false;
1896 let mut title = None;
1897 let mut cross_between = None;
1898
1899 loop {
1900 match reader.read_event()? {
1901 Event::Empty(child) if child.local_name().as_ref() == b"axId" => {
1902 id = raw_attribute(&child, b"val")
1903 .and_then(|v| v.parse().ok())
1904 .unwrap_or(0);
1905 }
1906 Event::Start(child) if child.local_name().as_ref() == b"axId" => {
1907 id = raw_attribute(&child, b"val")
1908 .and_then(|v| v.parse().ok())
1909 .unwrap_or(0);
1910 skip_subtree(reader)?;
1911 }
1912
1913 Event::Start(start) if start.local_name().as_ref() == b"scaling" => {
1914 let scaling = parse_scaling(reader)?;
1915 log_base = scaling.log_base;
1916 reversed = scaling.reversed;
1917 max = scaling.max;
1918 min = scaling.min;
1919 }
1920
1921 Event::Empty(child) if child.local_name().as_ref() == b"axPos" => {
1922 position = raw_attribute(&child, b"val")
1923 .and_then(|v| AxisPosition::from_xml_token(&v))
1924 .unwrap_or(AxisPosition::Left);
1925 }
1926 Event::Start(child) if child.local_name().as_ref() == b"axPos" => {
1927 position = raw_attribute(&child, b"val")
1928 .and_then(|v| AxisPosition::from_xml_token(&v))
1929 .unwrap_or(AxisPosition::Left);
1930 skip_subtree(reader)?;
1931 }
1932
1933 Event::Empty(child) if child.local_name().as_ref() == b"majorGridlines" => {
1934 major_gridlines = true;
1935 }
1936 Event::Start(child) if child.local_name().as_ref() == b"majorGridlines" => {
1937 major_gridlines = true;
1938 skip_subtree(reader)?;
1939 }
1940
1941 Event::Empty(child) if child.local_name().as_ref() == b"minorGridlines" => {
1942 minor_gridlines = true;
1943 }
1944 Event::Start(child) if child.local_name().as_ref() == b"minorGridlines" => {
1945 minor_gridlines = true;
1946 skip_subtree(reader)?;
1947 }
1948
1949 Event::Start(start) if start.local_name().as_ref() == b"title" => {
1950 title = Some(parse_title(reader)?);
1951 }
1952 Event::Empty(start) if start.local_name().as_ref() == b"title" => {
1953 title = Some(Title::new());
1954 }
1955
1956 Event::Empty(child) if child.local_name().as_ref() == b"crossAx" => {
1957 cross_axis_id = raw_attribute(&child, b"val")
1958 .and_then(|v| v.parse().ok())
1959 .unwrap_or(0);
1960 }
1961 Event::Start(child) if child.local_name().as_ref() == b"crossAx" => {
1962 cross_axis_id = raw_attribute(&child, b"val")
1963 .and_then(|v| v.parse().ok())
1964 .unwrap_or(0);
1965 skip_subtree(reader)?;
1966 }
1967
1968 Event::Empty(child) if child.local_name().as_ref() == b"crossBetween" => {
1969 cross_between =
1970 raw_attribute(&child, b"val").and_then(|v| CrossBetween::from_xml_token(&v));
1971 }
1972 Event::Start(child) if child.local_name().as_ref() == b"crossBetween" => {
1973 cross_between =
1974 raw_attribute(&child, b"val").and_then(|v| CrossBetween::from_xml_token(&v));
1975 skip_subtree(reader)?;
1976 }
1977
1978 Event::Start(_) => skip_subtree(reader)?,
1982 Event::Empty(_) => {}
1983 Event::End(_) | Event::Eof => break,
1984 _ => {}
1985 }
1986 }
1987
1988 let mut axis = ValueAxis::new(id, position, cross_axis_id);
1989 axis.log_base = log_base;
1990 axis.min = min;
1991 axis.max = max;
1992 axis.reversed = reversed;
1993 axis.major_gridlines = major_gridlines;
1994 axis.minor_gridlines = minor_gridlines;
1995 axis.title = title;
1996 axis.cross_between = cross_between;
1997 Ok(axis)
1998}
1999
2000fn parse_axis_data_source(reader: &mut Reader) -> Result<Option<AxisDataSource>> {
2001 let mut result = None;
2002
2003 loop {
2004 match reader.read_event()? {
2005 Event::Start(start) if start.local_name().as_ref() == b"numRef" => {
2006 let (formula, cache) = parse_numeric_reference(reader)?;
2007 result = Some(AxisDataSource::Numeric(NumericDataSource::Reference {
2008 formula,
2009 cache,
2010 }));
2011 }
2012 Event::Start(start) if start.local_name().as_ref() == b"numLit" => {
2013 result = Some(AxisDataSource::Numeric(NumericDataSource::Literal(
2014 parse_numeric_data(reader)?,
2015 )));
2016 }
2017 Event::Start(start) if start.local_name().as_ref() == b"strRef" => {
2018 let (formula, cache) = parse_string_reference(reader)?;
2019 result = Some(AxisDataSource::String(StringDataSource::Reference {
2020 formula,
2021 cache,
2022 }));
2023 }
2024 Event::Start(start) if start.local_name().as_ref() == b"strLit" => {
2025 result = Some(AxisDataSource::String(StringDataSource::Literal(
2026 parse_string_data(reader)?,
2027 )));
2028 }
2029 Event::Start(_) => skip_subtree(reader)?,
2031 Event::End(_) | Event::Eof => break,
2032 _ => {}
2033 }
2034 }
2035
2036 Ok(result)
2037}
2038
2039fn parse_numeric_data_source(reader: &mut Reader) -> Result<Option<NumericDataSource>> {
2040 let mut result = None;
2041
2042 loop {
2043 match reader.read_event()? {
2044 Event::Start(start) if start.local_name().as_ref() == b"numRef" => {
2045 let (formula, cache) = parse_numeric_reference(reader)?;
2046 result = Some(NumericDataSource::Reference { formula, cache });
2047 }
2048 Event::Start(start) if start.local_name().as_ref() == b"numLit" => {
2049 result = Some(NumericDataSource::Literal(parse_numeric_data(reader)?));
2050 }
2051 Event::Start(_) => skip_subtree(reader)?,
2052 Event::End(_) | Event::Eof => break,
2053 _ => {}
2054 }
2055 }
2056
2057 Ok(result)
2058}
2059
2060fn parse_numeric_reference(reader: &mut Reader) -> Result<(String, Option<NumericData>)> {
2061 let mut formula = String::new();
2062 let mut cache = None;
2063
2064 loop {
2065 match reader.read_event()? {
2066 Event::Start(start) if start.local_name().as_ref() == b"f" => {
2067 formula = read_text_content(reader, b"f")?;
2068 }
2069 Event::Start(start) if start.local_name().as_ref() == b"numCache" => {
2070 cache = Some(parse_numeric_data(reader)?);
2071 }
2072 Event::Start(_) => skip_subtree(reader)?,
2073 Event::End(end) if end.local_name().as_ref() == b"numRef" => break,
2074 Event::Eof => break,
2075 _ => {}
2076 }
2077 }
2078
2079 Ok((formula, cache))
2080}
2081
2082fn parse_string_reference(reader: &mut Reader) -> Result<(String, Option<StringData>)> {
2083 let mut formula = String::new();
2084 let mut cache = None;
2085
2086 loop {
2087 match reader.read_event()? {
2088 Event::Start(start) if start.local_name().as_ref() == b"f" => {
2089 formula = read_text_content(reader, b"f")?;
2090 }
2091 Event::Start(start) if start.local_name().as_ref() == b"strCache" => {
2092 cache = Some(parse_string_data(reader)?);
2093 }
2094 Event::Start(_) => skip_subtree(reader)?,
2095 Event::End(end) if end.local_name().as_ref() == b"strRef" => break,
2096 Event::Eof => break,
2097 _ => {}
2098 }
2099 }
2100
2101 Ok((formula, cache))
2102}
2103
2104fn parse_numeric_data(reader: &mut Reader) -> Result<NumericData> {
2105 let mut data = NumericData::new();
2106
2107 loop {
2108 match reader.read_event()? {
2109 Event::Start(start) if start.local_name().as_ref() == b"formatCode" => {
2110 data.format_code = Some(read_text_content(reader, b"formatCode")?);
2111 }
2112
2113 Event::Empty(child) if child.local_name().as_ref() == b"ptCount" => {
2114 data.point_count = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
2115 }
2116 Event::Start(child) if child.local_name().as_ref() == b"ptCount" => {
2117 data.point_count = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
2118 skip_subtree(reader)?;
2119 }
2120
2121 Event::Start(start) if start.local_name().as_ref() == b"pt" => {
2122 let index = raw_attribute(&start, b"idx")
2123 .and_then(|v| v.parse().ok())
2124 .unwrap_or(0);
2125 let format_code = raw_attribute(&start, b"formatCode");
2126 let value = parse_pt_value(reader)?;
2127 let mut point = NumericPoint::new(index, value);
2128 point.format_code = format_code;
2129 data.points.push(point);
2130 }
2131
2132 Event::Start(_) => skip_subtree(reader)?,
2133 Event::End(_) | Event::Eof => break,
2134 _ => {}
2135 }
2136 }
2137
2138 Ok(data)
2139}
2140
2141fn parse_string_data(reader: &mut Reader) -> Result<StringData> {
2142 let mut data = StringData::new();
2143
2144 loop {
2145 match reader.read_event()? {
2146 Event::Empty(child) if child.local_name().as_ref() == b"ptCount" => {
2147 data.point_count = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
2148 }
2149 Event::Start(child) if child.local_name().as_ref() == b"ptCount" => {
2150 data.point_count = raw_attribute(&child, b"val").and_then(|v| v.parse().ok());
2151 skip_subtree(reader)?;
2152 }
2153
2154 Event::Start(start) if start.local_name().as_ref() == b"pt" => {
2155 let index = raw_attribute(&start, b"idx")
2156 .and_then(|v| v.parse().ok())
2157 .unwrap_or(0);
2158 let value = parse_pt_value(reader)?;
2159 data.points.push(StringPoint { index, value });
2160 }
2161
2162 Event::Start(_) => skip_subtree(reader)?,
2163 Event::End(_) | Event::Eof => break,
2164 _ => {}
2165 }
2166 }
2167
2168 Ok(data)
2169}
2170
2171fn parse_pt_value(reader: &mut Reader) -> Result<String> {
2174 let mut value = String::new();
2175
2176 loop {
2177 match reader.read_event()? {
2178 Event::Start(start) if start.local_name().as_ref() == b"v" => {
2179 value = read_text_content(reader, b"v")?;
2180 }
2181 Event::Start(_) => skip_subtree(reader)?,
2182 Event::End(end) if end.local_name().as_ref() == b"pt" => break,
2183 Event::Eof => break,
2184 _ => {}
2185 }
2186 }
2187
2188 Ok(value)
2189}