1use crate::error::{Error, Result};
14use quick_xml::Reader;
15use quick_xml::events::Event;
16use std::io::{BufRead, Cursor};
17
18#[derive(Debug, Clone, Default)]
22pub struct MathZone {
23 pub elements: Vec<MathElement>,
25}
26
27impl MathZone {
28 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn text(&self) -> String {
35 self.elements.iter().map(|e| e.text()).collect()
36 }
37}
38
39impl ooxml_xml::FromXml for MathZone {
40 fn from_xml<R: BufRead>(
41 reader: &mut Reader<R>,
42 _start_tag: &quick_xml::events::BytesStart,
43 is_empty: bool,
44 ) -> std::result::Result<Self, ooxml_xml::ParseError> {
45 if is_empty {
46 return Ok(Self::default());
47 }
48 parse_math_zone_from_reader(reader).map_err(|e| match e {
49 Error::Xml(xml_err) => ooxml_xml::ParseError::Xml(xml_err),
50 Error::Invalid(msg) => ooxml_xml::ParseError::InvalidValue(msg),
51 })
52 }
53}
54
55#[derive(Debug, Clone)]
57pub enum MathElement {
58 Run(MathRun),
60 Fraction(Fraction),
62 Radical(Radical),
64 Nary(Nary),
66 Subscript(Script),
68 Superscript(Script),
70 SubSuperscript(SubSuperscript),
72 PreScript(PreScript),
74 Delimiter(Delimiter),
76 Matrix(Matrix),
78 Function(Function),
80 Accent(Accent),
82 Bar(Bar),
84 Box(MathBox),
86 BorderBox(BorderBox),
88 EquationArray(EquationArray),
90 LowerLimit(Limit),
92 UpperLimit(Limit),
94 GroupChar(GroupChar),
96 Phantom(Phantom),
98}
99
100impl MathElement {
101 pub fn text(&self) -> String {
103 match self {
104 MathElement::Run(r) => r.text.clone(),
105 MathElement::Fraction(f) => {
106 format!("({})/({})", f.numerator.text(), f.denominator.text())
107 }
108 MathElement::Radical(r) => {
109 if r.degree.elements.is_empty() {
110 format!("sqrt({})", r.base.text())
111 } else {
112 format!("root[{}]({})", r.degree.text(), r.base.text())
113 }
114 }
115 MathElement::Nary(n) => {
116 let op = n.operator.as_deref().unwrap_or("∑");
117 format!(
118 "{}[{},{}]({})",
119 op,
120 n.subscript.text(),
121 n.superscript.text(),
122 n.base.text()
123 )
124 }
125 MathElement::Subscript(s) => format!("{}_{}", s.base.text(), s.script.text()),
126 MathElement::Superscript(s) => format!("{}^{}", s.base.text(), s.script.text()),
127 MathElement::SubSuperscript(s) => format!(
128 "{}_{}^{}",
129 s.base.text(),
130 s.subscript.text(),
131 s.superscript.text()
132 ),
133 MathElement::PreScript(p) => format!(
134 "_{}^{}{}",
135 p.subscript.text(),
136 p.superscript.text(),
137 p.base.text()
138 ),
139 MathElement::Delimiter(d) => {
140 let begin = d.begin_char.as_deref().unwrap_or("(");
141 let end = d.end_char.as_deref().unwrap_or(")");
142 let inner: Vec<_> = d.elements.iter().map(|e| e.text()).collect();
143 format!(
144 "{}{}{}",
145 begin,
146 inner.join(d.separator_char.as_deref().unwrap_or(",")),
147 end
148 )
149 }
150 MathElement::Matrix(m) => {
151 let rows: Vec<_> = m
152 .rows
153 .iter()
154 .map(|row| {
155 let cells: Vec<_> = row.iter().map(|c| c.text()).collect();
156 cells.join(", ")
157 })
158 .collect();
159 format!("[{}]", rows.join("; "))
160 }
161 MathElement::Function(f) => format!("{}({})", f.name.text(), f.argument.text()),
162 MathElement::Accent(a) => format!(
163 "{}({})",
164 a.character.as_deref().unwrap_or("^"),
165 a.base.text()
166 ),
167 MathElement::Bar(b) => format!("bar({})", b.base.text()),
168 MathElement::Box(b) => b.content.text(),
169 MathElement::BorderBox(b) => format!("[{}]", b.content.text()),
170 MathElement::EquationArray(e) => {
171 let eqs: Vec<_> = e.equations.iter().map(|eq| eq.text()).collect();
172 eqs.join("\n")
173 }
174 MathElement::LowerLimit(l) => format!("lim_{}({})", l.limit.text(), l.base.text()),
175 MathElement::UpperLimit(l) => format!("lim^{}({})", l.limit.text(), l.base.text()),
176 MathElement::GroupChar(g) => format!(
177 "group[{}]({})",
178 g.character.as_deref().unwrap_or("⏟"),
179 g.base.text()
180 ),
181 MathElement::Phantom(p) => p.content.text(),
182 }
183 }
184}
185
186#[derive(Debug, Clone, Default)]
188pub struct MathRun {
189 pub text: String,
191 pub properties: Option<MathRunProperties>,
193}
194
195#[derive(Debug, Clone, Default)]
197pub struct MathRunProperties {
198 pub script: Option<MathScript>,
200 pub style: Option<MathStyle>,
202 pub literal: bool,
204 pub normal: bool,
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
213pub enum MathScript {
214 Roman,
216 Script,
218 Fraktur,
220 DoubleStruck,
222 SansSerif,
224 Monospace,
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233pub enum MathStyle {
234 Plain,
236 Bold,
238 Italic,
240 BoldItalic,
242}
243
244#[derive(Debug, Clone, Default)]
246pub struct Fraction {
247 pub numerator: MathZone,
249 pub denominator: MathZone,
251 pub fraction_type: Option<FractionType>,
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257pub enum FractionType {
258 Bar,
260 Skewed,
262 Linear,
264 NoBar,
266}
267
268#[derive(Debug, Clone, Default)]
270pub struct Radical {
271 pub base: MathZone,
273 pub degree: MathZone,
275 pub hide_degree: bool,
277}
278
279#[derive(Debug, Clone, Default)]
281pub struct Nary {
282 pub operator: Option<String>,
284 pub subscript: MathZone,
286 pub superscript: MathZone,
288 pub base: MathZone,
290 pub limit_location: Option<LimitLocation>,
292 pub grow: bool,
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub enum LimitLocation {
299 UnderOver,
301 SubSup,
303}
304
305#[derive(Debug, Clone, Default)]
307pub struct Script {
308 pub base: MathZone,
310 pub script: MathZone,
312}
313
314#[derive(Debug, Clone, Default)]
316pub struct SubSuperscript {
317 pub base: MathZone,
319 pub subscript: MathZone,
321 pub superscript: MathZone,
323}
324
325#[derive(Debug, Clone, Default)]
327pub struct PreScript {
328 pub subscript: MathZone,
330 pub superscript: MathZone,
332 pub base: MathZone,
334}
335
336#[derive(Debug, Clone, Default)]
338pub struct Delimiter {
339 pub begin_char: Option<String>,
341 pub separator_char: Option<String>,
343 pub end_char: Option<String>,
345 pub elements: Vec<MathZone>,
347 pub grow: bool,
349}
350
351#[derive(Debug, Clone, Default)]
353pub struct Matrix {
354 pub rows: Vec<Vec<MathZone>>,
356}
357
358#[derive(Debug, Clone, Default)]
360pub struct Function {
361 pub name: MathZone,
363 pub argument: MathZone,
365}
366
367#[derive(Debug, Clone, Default)]
369pub struct Accent {
370 pub character: Option<String>,
372 pub base: MathZone,
374}
375
376#[derive(Debug, Clone, Default)]
378pub struct Bar {
379 pub base: MathZone,
381 pub position: Option<VerticalPosition>,
383}
384
385#[derive(Debug, Clone, Copy, PartialEq, Eq)]
389pub enum VerticalPosition {
390 Top,
392 Bottom,
394}
395
396#[derive(Debug, Clone, Default)]
398pub struct MathBox {
399 pub content: MathZone,
401}
402
403#[derive(Debug, Clone, Default)]
405pub struct BorderBox {
406 pub content: MathZone,
408 pub hide_top: bool,
410 pub hide_bottom: bool,
411 pub hide_left: bool,
412 pub hide_right: bool,
413}
414
415#[derive(Debug, Clone, Default)]
417pub struct EquationArray {
418 pub equations: Vec<MathZone>,
420}
421
422#[derive(Debug, Clone, Default)]
424pub struct Limit {
425 pub base: MathZone,
427 pub limit: MathZone,
429}
430
431#[derive(Debug, Clone, Default)]
433pub struct GroupChar {
434 pub character: Option<String>,
436 pub position: Option<VerticalPosition>,
438 pub base: MathZone,
440}
441
442#[derive(Debug, Clone, Default)]
444pub struct Phantom {
445 pub content: MathZone,
447 pub show: bool,
449}
450
451pub fn parse_math_zone(xml: &[u8]) -> Result<MathZone> {
457 let mut reader = Reader::from_reader(Cursor::new(xml));
458 parse_math_zone_from_reader(&mut reader)
459}
460
461pub fn parse_math_zone_from_reader<R: BufRead>(reader: &mut Reader<R>) -> Result<MathZone> {
463 let mut buf = Vec::new();
464 let mut zone = MathZone::new();
465
466 loop {
467 match reader.read_event_into(&mut buf) {
468 Ok(Event::Start(e)) => {
469 let name = e.name();
470 let name = name.as_ref();
471 if let Some(element) = parse_math_element_start(name, reader)? {
472 zone.elements.push(element);
473 }
474 }
475 Ok(Event::Empty(e)) => {
476 let _ = e;
478 }
479 Ok(Event::End(e)) => {
480 let name = e.name();
481 if name.as_ref() == b"m:oMath" || name.as_ref() == b"oMath" {
482 break;
483 }
484 }
485 Ok(Event::Eof) => break,
486 Err(e) => return Err(Error::Xml(e)),
487 _ => {}
488 }
489 buf.clear();
490 }
491
492 Ok(zone)
493}
494
495fn parse_math_element_start<R: BufRead>(
497 name: &[u8],
498 reader: &mut Reader<R>,
499) -> Result<Option<MathElement>> {
500 match name {
501 b"m:r" | b"r" => Ok(Some(MathElement::Run(parse_math_run(reader)?))),
502 b"m:f" | b"f" => Ok(Some(MathElement::Fraction(parse_fraction(reader)?))),
503 b"m:rad" | b"rad" => Ok(Some(MathElement::Radical(parse_radical(reader)?))),
504 b"m:nary" | b"nary" => Ok(Some(MathElement::Nary(parse_nary(reader)?))),
505 b"m:sSub" | b"sSub" => Ok(Some(MathElement::Subscript(parse_script(
506 reader, b"m:sSub",
507 )?))),
508 b"m:sSup" | b"sSup" => Ok(Some(MathElement::Superscript(parse_script(
509 reader, b"m:sSup",
510 )?))),
511 b"m:sSubSup" | b"sSubSup" => Ok(Some(MathElement::SubSuperscript(parse_sub_superscript(
512 reader,
513 )?))),
514 b"m:sPre" | b"sPre" => Ok(Some(MathElement::PreScript(parse_pre_script(reader)?))),
515 b"m:d" | b"d" => Ok(Some(MathElement::Delimiter(parse_delimiter(reader)?))),
516 b"m:m" | b"m" => Ok(Some(MathElement::Matrix(parse_matrix(reader)?))),
517 b"m:func" | b"func" => Ok(Some(MathElement::Function(parse_function(reader)?))),
518 b"m:acc" | b"acc" => Ok(Some(MathElement::Accent(parse_accent(reader)?))),
519 b"m:bar" | b"bar" => Ok(Some(MathElement::Bar(parse_bar(reader)?))),
520 b"m:box" | b"box" => Ok(Some(MathElement::Box(parse_math_box(reader)?))),
521 b"m:borderBox" | b"borderBox" => {
522 Ok(Some(MathElement::BorderBox(parse_border_box(reader)?)))
523 }
524 b"m:eqArr" | b"eqArr" => Ok(Some(MathElement::EquationArray(parse_equation_array(
525 reader,
526 )?))),
527 b"m:limLow" | b"limLow" => Ok(Some(MathElement::LowerLimit(parse_limit(
528 reader,
529 b"m:limLow",
530 )?))),
531 b"m:limUpp" | b"limUpp" => Ok(Some(MathElement::UpperLimit(parse_limit(
532 reader,
533 b"m:limUpp",
534 )?))),
535 b"m:groupChr" | b"groupChr" => Ok(Some(MathElement::GroupChar(parse_group_char(reader)?))),
536 b"m:phant" | b"phant" => Ok(Some(MathElement::Phantom(parse_phantom(reader)?))),
537 _ => Ok(None),
538 }
539}
540
541fn parse_math_run<R: BufRead>(reader: &mut Reader<R>) -> Result<MathRun> {
543 let mut buf = Vec::new();
544 let mut run = MathRun::default();
545 let mut in_text = false;
546
547 loop {
548 match reader.read_event_into(&mut buf) {
549 Ok(Event::Start(e)) => {
550 let name = e.name();
551 if name.as_ref() == b"m:t" || name.as_ref() == b"t" {
552 in_text = true;
553 }
554 }
555 Ok(Event::Text(e)) => {
556 if in_text {
557 run.text.push_str(&e.decode().unwrap_or_default());
558 }
559 }
560 Ok(Event::End(e)) => {
561 let name = e.name();
562 let name = name.as_ref();
563 if name == b"m:t" || name == b"t" {
564 in_text = false;
565 } else if name == b"m:r" || name == b"r" {
566 break;
567 }
568 }
569 Ok(Event::Eof) => break,
570 Err(e) => return Err(Error::Xml(e)),
571 _ => {}
572 }
573 buf.clear();
574 }
575
576 Ok(run)
577}
578
579fn parse_math_arg<R: BufRead>(reader: &mut Reader<R>, end_tag: &[u8]) -> Result<MathZone> {
581 let mut buf = Vec::new();
582 let mut zone = MathZone::new();
583
584 loop {
585 match reader.read_event_into(&mut buf) {
586 Ok(Event::Start(e)) => {
587 let name = e.name();
588 let name = name.as_ref();
589 if let Some(element) = parse_math_element_start(name, reader)? {
590 zone.elements.push(element);
591 }
592 }
593 Ok(Event::End(e)) => {
594 let name = e.name();
595 if name.as_ref() == end_tag {
596 break;
597 }
598 }
599 Ok(Event::Eof) => break,
600 Err(e) => return Err(Error::Xml(e)),
601 _ => {}
602 }
603 buf.clear();
604 }
605
606 Ok(zone)
607}
608
609fn parse_fraction<R: BufRead>(reader: &mut Reader<R>) -> Result<Fraction> {
611 let mut buf = Vec::new();
612 let mut fraction = Fraction::default();
613
614 loop {
615 match reader.read_event_into(&mut buf) {
616 Ok(Event::Start(e)) => {
617 let name = e.name();
618 let name = name.as_ref();
619 match name {
620 b"m:num" | b"num" => fraction.numerator = parse_math_arg(reader, name)?,
621 b"m:den" | b"den" => fraction.denominator = parse_math_arg(reader, name)?,
622 _ => {}
623 }
624 }
625 Ok(Event::End(e)) => {
626 let name = e.name();
627 if name.as_ref() == b"m:f" || name.as_ref() == b"f" {
628 break;
629 }
630 }
631 Ok(Event::Eof) => break,
632 Err(e) => return Err(Error::Xml(e)),
633 _ => {}
634 }
635 buf.clear();
636 }
637
638 Ok(fraction)
639}
640
641fn parse_radical<R: BufRead>(reader: &mut Reader<R>) -> Result<Radical> {
643 let mut buf = Vec::new();
644 let mut radical = Radical::default();
645
646 loop {
647 match reader.read_event_into(&mut buf) {
648 Ok(Event::Start(e)) => {
649 let name = e.name();
650 let name = name.as_ref();
651 match name {
652 b"m:e" | b"e" => radical.base = parse_math_arg(reader, name)?,
653 b"m:deg" | b"deg" => radical.degree = parse_math_arg(reader, name)?,
654 _ => {}
655 }
656 }
657 Ok(Event::End(e)) => {
658 let name = e.name();
659 if name.as_ref() == b"m:rad" || name.as_ref() == b"rad" {
660 break;
661 }
662 }
663 Ok(Event::Eof) => break,
664 Err(e) => return Err(Error::Xml(e)),
665 _ => {}
666 }
667 buf.clear();
668 }
669
670 Ok(radical)
671}
672
673fn parse_nary<R: BufRead>(reader: &mut Reader<R>) -> Result<Nary> {
675 let mut buf = Vec::new();
676 let mut nary = Nary::default();
677
678 loop {
679 match reader.read_event_into(&mut buf) {
680 Ok(Event::Start(e)) => {
681 let name = e.name();
682 let name = name.as_ref();
683 match name {
684 b"m:e" | b"e" => nary.base = parse_math_arg(reader, name)?,
685 b"m:sub" | b"sub" => nary.subscript = parse_math_arg(reader, name)?,
686 b"m:sup" | b"sup" => nary.superscript = parse_math_arg(reader, name)?,
687 _ => {}
688 }
689 }
690 Ok(Event::Empty(e)) => {
691 let name = e.name();
692 if name.as_ref() == b"m:chr" || name.as_ref() == b"chr" {
693 for attr in e.attributes().filter_map(|a| a.ok()) {
694 if attr.key.as_ref() == b"m:val" || attr.key.as_ref() == b"val" {
695 nary.operator = Some(String::from_utf8_lossy(&attr.value).into_owned());
696 }
697 }
698 }
699 }
700 Ok(Event::End(e)) => {
701 let name = e.name();
702 if name.as_ref() == b"m:nary" || name.as_ref() == b"nary" {
703 break;
704 }
705 }
706 Ok(Event::Eof) => break,
707 Err(e) => return Err(Error::Xml(e)),
708 _ => {}
709 }
710 buf.clear();
711 }
712
713 Ok(nary)
714}
715
716fn parse_script<R: BufRead>(reader: &mut Reader<R>, end_tag: &[u8]) -> Result<Script> {
718 let mut buf = Vec::new();
719 let mut script = Script::default();
720 let end_local = if end_tag.starts_with(b"m:") {
721 &end_tag[2..]
722 } else {
723 end_tag
724 };
725
726 loop {
727 match reader.read_event_into(&mut buf) {
728 Ok(Event::Start(e)) => {
729 let name = e.name();
730 let name = name.as_ref();
731 match name {
732 b"m:e" | b"e" => script.base = parse_math_arg(reader, name)?,
733 b"m:sub" | b"sub" | b"m:sup" | b"sup" => {
734 script.script = parse_math_arg(reader, name)?
735 }
736 _ => {}
737 }
738 }
739 Ok(Event::End(e)) => {
740 let name = e.name();
741 let name = name.as_ref();
742 if name == end_tag || name == end_local {
743 break;
744 }
745 }
746 Ok(Event::Eof) => break,
747 Err(e) => return Err(Error::Xml(e)),
748 _ => {}
749 }
750 buf.clear();
751 }
752
753 Ok(script)
754}
755
756fn parse_sub_superscript<R: BufRead>(reader: &mut Reader<R>) -> Result<SubSuperscript> {
758 let mut buf = Vec::new();
759 let mut result = SubSuperscript::default();
760
761 loop {
762 match reader.read_event_into(&mut buf) {
763 Ok(Event::Start(e)) => {
764 let name = e.name();
765 let name = name.as_ref();
766 match name {
767 b"m:e" | b"e" => result.base = parse_math_arg(reader, name)?,
768 b"m:sub" | b"sub" => result.subscript = parse_math_arg(reader, name)?,
769 b"m:sup" | b"sup" => result.superscript = parse_math_arg(reader, name)?,
770 _ => {}
771 }
772 }
773 Ok(Event::End(e)) => {
774 let name = e.name();
775 if name.as_ref() == b"m:sSubSup" || name.as_ref() == b"sSubSup" {
776 break;
777 }
778 }
779 Ok(Event::Eof) => break,
780 Err(e) => return Err(Error::Xml(e)),
781 _ => {}
782 }
783 buf.clear();
784 }
785
786 Ok(result)
787}
788
789fn parse_pre_script<R: BufRead>(reader: &mut Reader<R>) -> Result<PreScript> {
791 let mut buf = Vec::new();
792 let mut result = PreScript::default();
793
794 loop {
795 match reader.read_event_into(&mut buf) {
796 Ok(Event::Start(e)) => {
797 let name = e.name();
798 let name = name.as_ref();
799 match name {
800 b"m:e" | b"e" => result.base = parse_math_arg(reader, name)?,
801 b"m:sub" | b"sub" => result.subscript = parse_math_arg(reader, name)?,
802 b"m:sup" | b"sup" => result.superscript = parse_math_arg(reader, name)?,
803 _ => {}
804 }
805 }
806 Ok(Event::End(e)) => {
807 let name = e.name();
808 if name.as_ref() == b"m:sPre" || name.as_ref() == b"sPre" {
809 break;
810 }
811 }
812 Ok(Event::Eof) => break,
813 Err(e) => return Err(Error::Xml(e)),
814 _ => {}
815 }
816 buf.clear();
817 }
818
819 Ok(result)
820}
821
822fn parse_delimiter<R: BufRead>(reader: &mut Reader<R>) -> Result<Delimiter> {
824 let mut buf = Vec::new();
825 let mut delimiter = Delimiter::default();
826
827 loop {
828 match reader.read_event_into(&mut buf) {
829 Ok(Event::Start(e)) => {
830 let name = e.name();
831 let name = name.as_ref();
832 if name == b"m:e" || name == b"e" {
833 delimiter.elements.push(parse_math_arg(reader, name)?);
834 }
835 }
836 Ok(Event::Empty(e)) => {
837 let name = e.name();
838 let name = name.as_ref();
839 for attr in e.attributes().filter_map(|a| a.ok()) {
840 let val = String::from_utf8_lossy(&attr.value).into_owned();
841 if attr.key.as_ref() == b"m:val" || attr.key.as_ref() == b"val" {
842 match name {
843 b"m:begChr" | b"begChr" => delimiter.begin_char = Some(val),
844 b"m:sepChr" | b"sepChr" => delimiter.separator_char = Some(val),
845 b"m:endChr" | b"endChr" => delimiter.end_char = Some(val),
846 _ => {}
847 }
848 }
849 }
850 }
851 Ok(Event::End(e)) => {
852 let name = e.name();
853 if name.as_ref() == b"m:d" || name.as_ref() == b"d" {
854 break;
855 }
856 }
857 Ok(Event::Eof) => break,
858 Err(e) => return Err(Error::Xml(e)),
859 _ => {}
860 }
861 buf.clear();
862 }
863
864 Ok(delimiter)
865}
866
867fn parse_matrix<R: BufRead>(reader: &mut Reader<R>) -> Result<Matrix> {
869 let mut buf = Vec::new();
870 let mut matrix = Matrix::default();
871 let mut current_row: Vec<MathZone> = Vec::new();
872 let mut in_row = false;
873
874 loop {
875 match reader.read_event_into(&mut buf) {
876 Ok(Event::Start(e)) => {
877 let name = e.name();
878 let name = name.as_ref();
879 match name {
880 b"m:mr" | b"mr" => {
881 in_row = true;
882 current_row = Vec::new();
883 }
884 b"m:e" | b"e" if in_row => {
885 current_row.push(parse_math_arg(reader, name)?);
886 }
887 _ => {}
888 }
889 }
890 Ok(Event::End(e)) => {
891 let name = e.name();
892 let name = name.as_ref();
893 match name {
894 b"m:mr" | b"mr" => {
895 matrix.rows.push(std::mem::take(&mut current_row));
896 in_row = false;
897 }
898 b"m:m" => break,
899 _ => {}
900 }
901 }
902 Ok(Event::Eof) => break,
903 Err(e) => return Err(Error::Xml(e)),
904 _ => {}
905 }
906 buf.clear();
907 }
908
909 Ok(matrix)
910}
911
912fn parse_function<R: BufRead>(reader: &mut Reader<R>) -> Result<Function> {
914 let mut buf = Vec::new();
915 let mut function = Function::default();
916
917 loop {
918 match reader.read_event_into(&mut buf) {
919 Ok(Event::Start(e)) => {
920 let name = e.name();
921 let name = name.as_ref();
922 match name {
923 b"m:fName" | b"fName" => function.name = parse_math_arg(reader, name)?,
924 b"m:e" | b"e" => function.argument = parse_math_arg(reader, name)?,
925 _ => {}
926 }
927 }
928 Ok(Event::End(e)) => {
929 let name = e.name();
930 if name.as_ref() == b"m:func" || name.as_ref() == b"func" {
931 break;
932 }
933 }
934 Ok(Event::Eof) => break,
935 Err(e) => return Err(Error::Xml(e)),
936 _ => {}
937 }
938 buf.clear();
939 }
940
941 Ok(function)
942}
943
944fn parse_accent<R: BufRead>(reader: &mut Reader<R>) -> Result<Accent> {
946 let mut buf = Vec::new();
947 let mut accent = Accent::default();
948
949 loop {
950 match reader.read_event_into(&mut buf) {
951 Ok(Event::Start(e)) => {
952 let name = e.name();
953 let name = name.as_ref();
954 if name == b"m:e" || name == b"e" {
955 accent.base = parse_math_arg(reader, name)?;
956 }
957 }
958 Ok(Event::Empty(e)) => {
959 let name = e.name();
960 if name.as_ref() == b"m:chr" || name.as_ref() == b"chr" {
961 for attr in e.attributes().filter_map(|a| a.ok()) {
962 if attr.key.as_ref() == b"m:val" || attr.key.as_ref() == b"val" {
963 accent.character =
964 Some(String::from_utf8_lossy(&attr.value).into_owned());
965 }
966 }
967 }
968 }
969 Ok(Event::End(e)) => {
970 let name = e.name();
971 if name.as_ref() == b"m:acc" || name.as_ref() == b"acc" {
972 break;
973 }
974 }
975 Ok(Event::Eof) => break,
976 Err(e) => return Err(Error::Xml(e)),
977 _ => {}
978 }
979 buf.clear();
980 }
981
982 Ok(accent)
983}
984
985fn parse_bar<R: BufRead>(reader: &mut Reader<R>) -> Result<Bar> {
987 let mut buf = Vec::new();
988 let mut bar = Bar::default();
989
990 loop {
991 match reader.read_event_into(&mut buf) {
992 Ok(Event::Start(e)) => {
993 let name = e.name();
994 let name = name.as_ref();
995 if name == b"m:e" || name == b"e" {
996 bar.base = parse_math_arg(reader, name)?;
997 }
998 }
999 Ok(Event::End(e)) => {
1000 let name = e.name();
1001 if name.as_ref() == b"m:bar" || name.as_ref() == b"bar" {
1002 break;
1003 }
1004 }
1005 Ok(Event::Eof) => break,
1006 Err(e) => return Err(Error::Xml(e)),
1007 _ => {}
1008 }
1009 buf.clear();
1010 }
1011
1012 Ok(bar)
1013}
1014
1015fn parse_math_box<R: BufRead>(reader: &mut Reader<R>) -> Result<MathBox> {
1017 let mut buf = Vec::new();
1018 let mut result = MathBox::default();
1019
1020 loop {
1021 match reader.read_event_into(&mut buf) {
1022 Ok(Event::Start(e)) => {
1023 let name = e.name();
1024 let name = name.as_ref();
1025 if name == b"m:e" || name == b"e" {
1026 result.content = parse_math_arg(reader, name)?;
1027 }
1028 }
1029 Ok(Event::End(e)) => {
1030 let name = e.name();
1031 if name.as_ref() == b"m:box" || name.as_ref() == b"box" {
1032 break;
1033 }
1034 }
1035 Ok(Event::Eof) => break,
1036 Err(e) => return Err(Error::Xml(e)),
1037 _ => {}
1038 }
1039 buf.clear();
1040 }
1041
1042 Ok(result)
1043}
1044
1045fn parse_border_box<R: BufRead>(reader: &mut Reader<R>) -> Result<BorderBox> {
1047 let mut buf = Vec::new();
1048 let mut result = BorderBox::default();
1049
1050 loop {
1051 match reader.read_event_into(&mut buf) {
1052 Ok(Event::Start(e)) => {
1053 let name = e.name();
1054 let name = name.as_ref();
1055 if name == b"m:e" || name == b"e" {
1056 result.content = parse_math_arg(reader, name)?;
1057 }
1058 }
1059 Ok(Event::End(e)) => {
1060 let name = e.name();
1061 if name.as_ref() == b"m:borderBox" || name.as_ref() == b"borderBox" {
1062 break;
1063 }
1064 }
1065 Ok(Event::Eof) => break,
1066 Err(e) => return Err(Error::Xml(e)),
1067 _ => {}
1068 }
1069 buf.clear();
1070 }
1071
1072 Ok(result)
1073}
1074
1075fn parse_equation_array<R: BufRead>(reader: &mut Reader<R>) -> Result<EquationArray> {
1077 let mut buf = Vec::new();
1078 let mut result = EquationArray::default();
1079
1080 loop {
1081 match reader.read_event_into(&mut buf) {
1082 Ok(Event::Start(e)) => {
1083 let name = e.name();
1084 let name = name.as_ref();
1085 if name == b"m:e" || name == b"e" {
1086 result.equations.push(parse_math_arg(reader, name)?);
1087 }
1088 }
1089 Ok(Event::End(e)) => {
1090 let name = e.name();
1091 if name.as_ref() == b"m:eqArr" || name.as_ref() == b"eqArr" {
1092 break;
1093 }
1094 }
1095 Ok(Event::Eof) => break,
1096 Err(e) => return Err(Error::Xml(e)),
1097 _ => {}
1098 }
1099 buf.clear();
1100 }
1101
1102 Ok(result)
1103}
1104
1105fn parse_limit<R: BufRead>(reader: &mut Reader<R>, end_tag: &[u8]) -> Result<Limit> {
1107 let mut buf = Vec::new();
1108 let mut result = Limit::default();
1109 let end_local = if end_tag.starts_with(b"m:") {
1110 &end_tag[2..]
1111 } else {
1112 end_tag
1113 };
1114
1115 loop {
1116 match reader.read_event_into(&mut buf) {
1117 Ok(Event::Start(e)) => {
1118 let name = e.name();
1119 let name = name.as_ref();
1120 match name {
1121 b"m:e" | b"e" => result.base = parse_math_arg(reader, name)?,
1122 b"m:lim" | b"lim" => result.limit = parse_math_arg(reader, name)?,
1123 _ => {}
1124 }
1125 }
1126 Ok(Event::End(e)) => {
1127 let name = e.name();
1128 let name = name.as_ref();
1129 if name == end_tag || name == end_local {
1130 break;
1131 }
1132 }
1133 Ok(Event::Eof) => break,
1134 Err(e) => return Err(Error::Xml(e)),
1135 _ => {}
1136 }
1137 buf.clear();
1138 }
1139
1140 Ok(result)
1141}
1142
1143fn parse_group_char<R: BufRead>(reader: &mut Reader<R>) -> Result<GroupChar> {
1145 let mut buf = Vec::new();
1146 let mut result = GroupChar::default();
1147
1148 loop {
1149 match reader.read_event_into(&mut buf) {
1150 Ok(Event::Start(e)) => {
1151 let name = e.name();
1152 let name = name.as_ref();
1153 if name == b"m:e" || name == b"e" {
1154 result.base = parse_math_arg(reader, name)?;
1155 }
1156 }
1157 Ok(Event::Empty(e)) => {
1158 let name = e.name();
1159 if name.as_ref() == b"m:chr" || name.as_ref() == b"chr" {
1160 for attr in e.attributes().filter_map(|a| a.ok()) {
1161 if attr.key.as_ref() == b"m:val" || attr.key.as_ref() == b"val" {
1162 result.character =
1163 Some(String::from_utf8_lossy(&attr.value).into_owned());
1164 }
1165 }
1166 }
1167 }
1168 Ok(Event::End(e)) => {
1169 let name = e.name();
1170 if name.as_ref() == b"m:groupChr" || name.as_ref() == b"groupChr" {
1171 break;
1172 }
1173 }
1174 Ok(Event::Eof) => break,
1175 Err(e) => return Err(Error::Xml(e)),
1176 _ => {}
1177 }
1178 buf.clear();
1179 }
1180
1181 Ok(result)
1182}
1183
1184fn parse_phantom<R: BufRead>(reader: &mut Reader<R>) -> Result<Phantom> {
1186 let mut buf = Vec::new();
1187 let mut result = Phantom::default();
1188
1189 loop {
1190 match reader.read_event_into(&mut buf) {
1191 Ok(Event::Start(e)) => {
1192 let name = e.name();
1193 let name = name.as_ref();
1194 if name == b"m:e" || name == b"e" {
1195 result.content = parse_math_arg(reader, name)?;
1196 }
1197 }
1198 Ok(Event::End(e)) => {
1199 let name = e.name();
1200 if name.as_ref() == b"m:phant" || name.as_ref() == b"phant" {
1201 break;
1202 }
1203 }
1204 Ok(Event::Eof) => break,
1205 Err(e) => return Err(Error::Xml(e)),
1206 _ => {}
1207 }
1208 buf.clear();
1209 }
1210
1211 Ok(result)
1212}
1213
1214pub fn serialize_math_zone(zone: &MathZone) -> String {
1220 let mut xml = String::new();
1221 xml.push_str("<m:oMath>");
1222 for element in &zone.elements {
1223 serialize_math_element(element, &mut xml);
1224 }
1225 xml.push_str("</m:oMath>");
1226 xml
1227}
1228
1229fn serialize_math_element(element: &MathElement, xml: &mut String) {
1231 match element {
1232 MathElement::Run(run) => serialize_math_run(run, xml),
1233 MathElement::Fraction(f) => {
1234 xml.push_str("<m:f>");
1235 xml.push_str("<m:num>");
1236 serialize_math_zone_content(&f.numerator, xml);
1237 xml.push_str("</m:num>");
1238 xml.push_str("<m:den>");
1239 serialize_math_zone_content(&f.denominator, xml);
1240 xml.push_str("</m:den>");
1241 xml.push_str("</m:f>");
1242 }
1243 MathElement::Radical(r) => {
1244 xml.push_str("<m:rad>");
1245 xml.push_str("<m:deg>");
1246 serialize_math_zone_content(&r.degree, xml);
1247 xml.push_str("</m:deg>");
1248 xml.push_str("<m:e>");
1249 serialize_math_zone_content(&r.base, xml);
1250 xml.push_str("</m:e>");
1251 xml.push_str("</m:rad>");
1252 }
1253 MathElement::Nary(n) => {
1254 xml.push_str("<m:nary>");
1255 if let Some(ref op) = n.operator {
1256 xml.push_str("<m:naryPr><m:chr m:val=\"");
1257 xml.push_str(&escape_xml(op));
1258 xml.push_str("\"/></m:naryPr>");
1259 }
1260 xml.push_str("<m:sub>");
1261 serialize_math_zone_content(&n.subscript, xml);
1262 xml.push_str("</m:sub>");
1263 xml.push_str("<m:sup>");
1264 serialize_math_zone_content(&n.superscript, xml);
1265 xml.push_str("</m:sup>");
1266 xml.push_str("<m:e>");
1267 serialize_math_zone_content(&n.base, xml);
1268 xml.push_str("</m:e>");
1269 xml.push_str("</m:nary>");
1270 }
1271 MathElement::Subscript(s) => {
1272 xml.push_str("<m:sSub>");
1273 xml.push_str("<m:e>");
1274 serialize_math_zone_content(&s.base, xml);
1275 xml.push_str("</m:e>");
1276 xml.push_str("<m:sub>");
1277 serialize_math_zone_content(&s.script, xml);
1278 xml.push_str("</m:sub>");
1279 xml.push_str("</m:sSub>");
1280 }
1281 MathElement::Superscript(s) => {
1282 xml.push_str("<m:sSup>");
1283 xml.push_str("<m:e>");
1284 serialize_math_zone_content(&s.base, xml);
1285 xml.push_str("</m:e>");
1286 xml.push_str("<m:sup>");
1287 serialize_math_zone_content(&s.script, xml);
1288 xml.push_str("</m:sup>");
1289 xml.push_str("</m:sSup>");
1290 }
1291 MathElement::SubSuperscript(s) => {
1292 xml.push_str("<m:sSubSup>");
1293 xml.push_str("<m:e>");
1294 serialize_math_zone_content(&s.base, xml);
1295 xml.push_str("</m:e>");
1296 xml.push_str("<m:sub>");
1297 serialize_math_zone_content(&s.subscript, xml);
1298 xml.push_str("</m:sub>");
1299 xml.push_str("<m:sup>");
1300 serialize_math_zone_content(&s.superscript, xml);
1301 xml.push_str("</m:sup>");
1302 xml.push_str("</m:sSubSup>");
1303 }
1304 MathElement::PreScript(p) => {
1305 xml.push_str("<m:sPre>");
1306 xml.push_str("<m:sub>");
1307 serialize_math_zone_content(&p.subscript, xml);
1308 xml.push_str("</m:sub>");
1309 xml.push_str("<m:sup>");
1310 serialize_math_zone_content(&p.superscript, xml);
1311 xml.push_str("</m:sup>");
1312 xml.push_str("<m:e>");
1313 serialize_math_zone_content(&p.base, xml);
1314 xml.push_str("</m:e>");
1315 xml.push_str("</m:sPre>");
1316 }
1317 MathElement::Delimiter(d) => {
1318 xml.push_str("<m:d>");
1319 if d.begin_char.as_deref() != Some("(") || d.end_char.as_deref() != Some(")") {
1320 xml.push_str("<m:dPr>");
1321 if let Some(ref beg) = d.begin_char {
1322 xml.push_str("<m:begChr m:val=\"");
1323 xml.push_str(&escape_xml(beg));
1324 xml.push_str("\"/>");
1325 }
1326 if let Some(ref end) = d.end_char {
1327 xml.push_str("<m:endChr m:val=\"");
1328 xml.push_str(&escape_xml(end));
1329 xml.push_str("\"/>");
1330 }
1331 xml.push_str("</m:dPr>");
1332 }
1333 for e in &d.elements {
1334 xml.push_str("<m:e>");
1335 serialize_math_zone_content(e, xml);
1336 xml.push_str("</m:e>");
1337 }
1338 xml.push_str("</m:d>");
1339 }
1340 MathElement::Matrix(m) => {
1341 xml.push_str("<m:m>");
1342 for row in &m.rows {
1343 xml.push_str("<m:mr>");
1344 for cell in row {
1345 xml.push_str("<m:e>");
1346 serialize_math_zone_content(cell, xml);
1347 xml.push_str("</m:e>");
1348 }
1349 xml.push_str("</m:mr>");
1350 }
1351 xml.push_str("</m:m>");
1352 }
1353 MathElement::Function(f) => {
1354 xml.push_str("<m:func>");
1355 xml.push_str("<m:fName>");
1356 serialize_math_zone_content(&f.name, xml);
1357 xml.push_str("</m:fName>");
1358 xml.push_str("<m:e>");
1359 serialize_math_zone_content(&f.argument, xml);
1360 xml.push_str("</m:e>");
1361 xml.push_str("</m:func>");
1362 }
1363 MathElement::Accent(a) => {
1364 xml.push_str("<m:acc>");
1365 if let Some(ref chr) = a.character {
1366 xml.push_str("<m:accPr><m:chr m:val=\"");
1367 xml.push_str(&escape_xml(chr));
1368 xml.push_str("\"/></m:accPr>");
1369 }
1370 xml.push_str("<m:e>");
1371 serialize_math_zone_content(&a.base, xml);
1372 xml.push_str("</m:e>");
1373 xml.push_str("</m:acc>");
1374 }
1375 MathElement::Bar(b) => {
1376 xml.push_str("<m:bar>");
1377 if b.position != Some(VerticalPosition::Top) {
1378 xml.push_str("<m:barPr><m:pos m:val=\"bot\"/></m:barPr>");
1379 }
1380 xml.push_str("<m:e>");
1381 serialize_math_zone_content(&b.base, xml);
1382 xml.push_str("</m:e>");
1383 xml.push_str("</m:bar>");
1384 }
1385 MathElement::Box(b) => {
1386 xml.push_str("<m:box>");
1387 xml.push_str("<m:e>");
1388 serialize_math_zone_content(&b.content, xml);
1389 xml.push_str("</m:e>");
1390 xml.push_str("</m:box>");
1391 }
1392 MathElement::BorderBox(b) => {
1393 xml.push_str("<m:borderBox>");
1394 xml.push_str("<m:e>");
1395 serialize_math_zone_content(&b.content, xml);
1396 xml.push_str("</m:e>");
1397 xml.push_str("</m:borderBox>");
1398 }
1399 MathElement::EquationArray(ea) => {
1400 xml.push_str("<m:eqArr>");
1401 for eq in &ea.equations {
1402 xml.push_str("<m:e>");
1403 serialize_math_zone_content(eq, xml);
1404 xml.push_str("</m:e>");
1405 }
1406 xml.push_str("</m:eqArr>");
1407 }
1408 MathElement::LowerLimit(l) => {
1409 xml.push_str("<m:limLow>");
1410 xml.push_str("<m:e>");
1411 serialize_math_zone_content(&l.base, xml);
1412 xml.push_str("</m:e>");
1413 xml.push_str("<m:lim>");
1414 serialize_math_zone_content(&l.limit, xml);
1415 xml.push_str("</m:lim>");
1416 xml.push_str("</m:limLow>");
1417 }
1418 MathElement::UpperLimit(l) => {
1419 xml.push_str("<m:limUpp>");
1420 xml.push_str("<m:e>");
1421 serialize_math_zone_content(&l.base, xml);
1422 xml.push_str("</m:e>");
1423 xml.push_str("<m:lim>");
1424 serialize_math_zone_content(&l.limit, xml);
1425 xml.push_str("</m:lim>");
1426 xml.push_str("</m:limUpp>");
1427 }
1428 MathElement::GroupChar(g) => {
1429 xml.push_str("<m:groupChr>");
1430 if let Some(ref chr) = g.character {
1431 xml.push_str("<m:groupChrPr><m:chr m:val=\"");
1432 xml.push_str(&escape_xml(chr));
1433 xml.push_str("\"/></m:groupChrPr>");
1434 }
1435 xml.push_str("<m:e>");
1436 serialize_math_zone_content(&g.base, xml);
1437 xml.push_str("</m:e>");
1438 xml.push_str("</m:groupChr>");
1439 }
1440 MathElement::Phantom(p) => {
1441 xml.push_str("<m:phant>");
1442 xml.push_str("<m:e>");
1443 serialize_math_zone_content(&p.content, xml);
1444 xml.push_str("</m:e>");
1445 xml.push_str("</m:phant>");
1446 }
1447 }
1448}
1449
1450fn serialize_math_zone_content(zone: &MathZone, xml: &mut String) {
1452 for element in &zone.elements {
1453 serialize_math_element(element, xml);
1454 }
1455}
1456
1457fn serialize_math_run(run: &MathRun, xml: &mut String) {
1459 xml.push_str("<m:r>");
1460 if let Some(ref props) = run.properties
1461 && let Some(style) = props.style
1462 {
1463 xml.push_str("<m:rPr>");
1464 xml.push_str("<m:sty m:val=\"");
1465 xml.push_str(match style {
1466 MathStyle::Plain => "p",
1467 MathStyle::Bold => "b",
1468 MathStyle::Italic => "i",
1469 MathStyle::BoldItalic => "bi",
1470 });
1471 xml.push_str("\"/>");
1472 xml.push_str("</m:rPr>");
1473 }
1474 xml.push_str("<m:t>");
1475 xml.push_str(&escape_xml(&run.text));
1476 xml.push_str("</m:t>");
1477 xml.push_str("</m:r>");
1478}
1479
1480fn escape_xml(s: &str) -> String {
1482 s.replace('&', "&")
1483 .replace('<', "<")
1484 .replace('>', ">")
1485 .replace('"', """)
1486}
1487
1488#[cfg(test)]
1489mod tests {
1490 use super::*;
1491
1492 #[test]
1493 fn test_parse_simple_math() {
1494 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1495 <m:r><m:t>x+y</m:t></m:r>
1496 </m:oMath>"#;
1497
1498 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1499 assert_eq!(zone.text(), "x+y");
1500 }
1501
1502 #[test]
1503 fn test_parse_fraction() {
1504 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1505 <m:f>
1506 <m:num><m:r><m:t>1</m:t></m:r></m:num>
1507 <m:den><m:r><m:t>2</m:t></m:r></m:den>
1508 </m:f>
1509 </m:oMath>"#;
1510
1511 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1512 assert_eq!(zone.text(), "(1)/(2)");
1513 }
1514
1515 #[test]
1516 fn test_parse_nested_fraction() {
1517 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1518 <m:f>
1519 <m:num>
1520 <m:r><m:t>a+</m:t></m:r>
1521 <m:f>
1522 <m:num><m:r><m:t>b</m:t></m:r></m:num>
1523 <m:den><m:r><m:t>c</m:t></m:r></m:den>
1524 </m:f>
1525 </m:num>
1526 <m:den><m:r><m:t>d</m:t></m:r></m:den>
1527 </m:f>
1528 </m:oMath>"#;
1529
1530 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1531 assert_eq!(zone.text(), "(a+(b)/(c))/(d)");
1532 }
1533
1534 #[test]
1535 fn test_parse_radical() {
1536 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1537 <m:rad>
1538 <m:deg></m:deg>
1539 <m:e><m:r><m:t>x</m:t></m:r></m:e>
1540 </m:rad>
1541 </m:oMath>"#;
1542
1543 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1544 assert_eq!(zone.text(), "sqrt(x)");
1545 }
1546
1547 #[test]
1548 fn test_parse_subscript() {
1549 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1550 <m:sSub>
1551 <m:e><m:r><m:t>x</m:t></m:r></m:e>
1552 <m:sub><m:r><m:t>i</m:t></m:r></m:sub>
1553 </m:sSub>
1554 </m:oMath>"#;
1555
1556 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1557 assert_eq!(zone.text(), "x_i");
1558 }
1559
1560 #[test]
1561 fn test_parse_delimiter() {
1562 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1563 <m:d>
1564 <m:e><m:r><m:t>a+b</m:t></m:r></m:e>
1565 </m:d>
1566 </m:oMath>"#;
1567
1568 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1569 assert_eq!(zone.text(), "(a+b)");
1570 }
1571
1572 #[test]
1573 fn test_parse_real_world_formula() {
1574 let xml = r#"<m:oMath xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
1577 <m:r><m:t> </m:t></m:r>
1578 <m:d>
1579 <m:e>
1580 <m:f>
1581 <m:num>
1582 <m:r><m:t>30+</m:t></m:r>
1583 <m:d>
1584 <m:e>
1585 <m:f>
1586 <m:num><m:r><m:t>90</m:t></m:r></m:num>
1587 <m:den><m:r><m:t>2</m:t></m:r></m:den>
1588 </m:f>
1589 </m:e>
1590 </m:d>
1591 </m:num>
1592 <m:den><m:r><m:t>900</m:t></m:r></m:den>
1593 </m:f>
1594 </m:e>
1595 </m:d>
1596 <m:r><m:t>*100=8%</m:t></m:r>
1597 </m:oMath>"#;
1598
1599 let zone = parse_math_zone(xml.as_bytes()).unwrap();
1600 let text = zone.text();
1601 assert!(text.contains("30+"));
1603 assert!(text.contains("90"));
1604 assert!(text.contains("900"));
1605 assert!(text.contains("*100=8%"));
1606 }
1607}