#[cfg(test)]
mod tests;
use crate::{Result, XmlWritable, XmlWriter};
use indexmap::{indexmap, IndexMap};
pub(crate) const APP_PACKAGE: &str =
"application/vnd.openxmlformats-package.";
pub(crate) const APP_DOCUMENT: &str =
"application/vnd.openxmlformats-officedocument.";
pub(crate) const APP_MSEXCEL: &str = "application/vnd.ms-excel.";
pub(crate) struct ContentTypes {
pub defaults: IndexMap<String, String>,
pub overrides: IndexMap<String, String>,
}
impl Default for ContentTypes {
fn default() -> Self {
let defaults = indexmap! {
"rels".to_string() =>
format!("{}relationships+xml", APP_PACKAGE),
"xml".to_string() => "application/xml".to_string(),
};
let overrides = indexmap! {
"/docProps/app.xml".to_string() =>
format!("{}extended-properties+xml", APP_DOCUMENT),
"/docProps/core.xml".to_string() =>
format!("{}core-properties+xml", APP_PACKAGE),
"/xl/styles.xml".to_string() =>
format!("{}spreadsheetml.styles+xml", APP_DOCUMENT),
"/xl/theme/theme1.xml".to_string() =>
format!("{}theme+xml", APP_DOCUMENT),
};
ContentTypes {
defaults,
overrides,
}
}
}
impl ContentTypes {
pub fn add_override(
&mut self,
key: impl Into<String>,
value: impl Into<String>,
) {
self.overrides.insert(key.into(), value.into());
}
pub fn add_default(
&mut self,
key: impl Into<String>,
value: impl Into<String>,
) {
self.defaults.insert(key.into(), value.into());
}
pub fn add_worksheet_name(&mut self, name: impl Into<String>) {
self.add_override(
name,
format!("{}spreadsheetml.worksheet+xml", APP_DOCUMENT),
);
}
pub fn add_shared_strings(&mut self) {
self.add_override(
"/xl/sharedStrings.xml",
format!("{}spreadsheetml.sharedStrings+xml", APP_DOCUMENT),
);
}
pub fn add_custom_properties(&mut self) {
self.add_override(
"/docProps/custom.xml",
format!("{}custom-properties+xml", APP_DOCUMENT),
);
}
pub fn add_calc_chain(&mut self) {
self.add_override(
"/xl/calcChain.xml",
format!("{}spreadsheetml.calcChain+xml", APP_DOCUMENT),
);
}
}
impl XmlWritable for ContentTypes {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "Types";
let attrs = indexmap! {
"xmlns" =>
"http://schemas.openxmlformats.org/package/2006/content-types",
};
w.start_tag_with_attrs(tag, attrs)?;
self.write_defaults(w)?;
self.write_overrides(w)?;
w.end_tag(tag)?;
Ok(())
}
}
impl ContentTypes {
fn write_defaults<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
for (k, v) in self.defaults.iter() {
let attrs = indexmap! {
"Extension" => k.as_str(),
"ContentType" => v.as_str(),
};
w.empty_tag_with_attrs("Default", attrs)?;
}
Ok(())
}
fn write_overrides<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
for (k, v) in self.overrides.iter() {
let attrs = indexmap! {
"PartName" => k.as_str(),
"ContentType" => v.as_str(),
};
w.empty_tag_with_attrs("Override", attrs)?;
}
Ok(())
}
}