use serde::Deserialize;
use crate::docx::parse::body_schema::TextXml;
use crate::model::{MathBlock, MathElement, MathRun};
#[derive(Deserialize, Default)]
pub(crate) struct OMathXml {
#[serde(rename = "$value", default)]
pub content: Vec<MathChildXml>,
}
#[derive(Deserialize, Default)]
pub(crate) struct OMathParaXml {
#[serde(rename = "oMath", default)]
pub math: Vec<OMathXml>,
}
#[derive(Deserialize)]
pub(crate) enum MathChildXml {
#[serde(rename = "r")]
Run(MathRunXml),
#[serde(rename = "sSup")]
SSup(SSupXml),
#[serde(rename = "f")]
Frac(FracXml),
#[serde(other)]
Other,
}
#[derive(Deserialize, Default)]
pub(crate) struct MathRunXml {
#[serde(rename = "t", default)]
pub texts: Vec<TextXml>,
}
#[derive(Deserialize, Default)]
pub(crate) struct SSupXml {
#[serde(rename = "e", default)]
pub base: Vec<MathArgXml>,
#[serde(rename = "sup", default)]
pub sup: Vec<MathArgXml>,
}
#[derive(Deserialize, Default)]
pub(crate) struct FracXml {
#[serde(rename = "num", default)]
pub num: Vec<MathArgXml>,
#[serde(rename = "den", default)]
pub den: Vec<MathArgXml>,
}
#[derive(Deserialize, Default)]
pub(crate) struct MathArgXml {
#[serde(rename = "$value", default)]
pub content: Vec<MathChildXml>,
}
impl From<OMathXml> for MathBlock {
fn from(x: OMathXml) -> Self {
MathBlock {
content: convert_children(x.content),
}
}
}
fn convert_children(children: Vec<MathChildXml>) -> Vec<MathElement> {
let mut out = Vec::new();
for child in children {
match child {
MathChildXml::Run(r) => {
let text: String = r.texts.iter().map(|t| t.content.as_str()).collect();
if !text.is_empty() {
out.push(MathElement::Run(MathRun { text }));
}
}
MathChildXml::SSup(s) => out.push(MathElement::Superscript {
base: convert_args(s.base),
sup: convert_args(s.sup),
}),
MathChildXml::Frac(f) => out.push(MathElement::Fraction {
num: convert_args(f.num),
den: convert_args(f.den),
}),
MathChildXml::Other => {
log::warn!("unsupported OMML construct skipped (only m:r, m:sSup, m:f render)");
}
}
}
out
}
fn convert_args(args: Vec<MathArgXml>) -> Vec<MathElement> {
args.into_iter()
.flat_map(|a| convert_children(a.content))
.collect()
}