use crate::error::OoxmlError;
use serde::{Deserialize, Serialize};
use std::io::prelude::*;
use std::{fmt, fs::File, path::Path};
pub const SHARED_STRINGS_TAG: &str = "sst";
pub const SHARED_STRING_TAG: &str = "si";
use crate::packaging::element::*;
use crate::packaging::namespace::Namespaces;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all(deserialize = "camelCase"), rename = "t")]
pub struct Value(String);
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all(deserialize = "camelCase"), rename = "si")]
pub struct SharedString {
t: Option<String>,
}
impl SharedString {
pub fn as_str(&self) -> &str {
match &self.t {
Some(s) => s.as_str(),
None => "",
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all(deserialize = "camelCase"), rename = "sst")]
pub struct SharedStringsPart {
count: usize,
unique_count: usize,
#[serde(flatten)]
namespaces: Namespaces,
#[serde(rename = "si")]
strings: Option<Vec<SharedString>>,
}
impl SharedStringsPart {
pub fn get_shared_string(&self, idx: usize) -> Option<&str> {
self.strings
.as_ref()
.and_then(|ss| ss.get(idx))
.map(|ss| ss.as_str())
}
}
impl OpenXmlElementInfo for SharedStringsPart {
fn tag_name() -> &'static str {
"sst"
}
fn element_type() -> OpenXmlElementType {
OpenXmlElementType::Root
}
}
impl OpenXmlDeserializeDefault for SharedStringsPart {}
impl fmt::Display for SharedStringsPart {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut container = Vec::new();
let mut cursor = std::io::Cursor::new(&mut container);
self.write(&mut cursor).expect("write xml to memory error");
let s = String::from_utf8_lossy(&container);
write!(f, "{}", s)?;
Ok(())
}
}
impl SharedStringsPart {
pub fn parse_from_xml_reader<R: BufRead>(reader: R) -> Self {
quick_xml::de::from_reader(reader).unwrap()
}
pub fn parse_from_xml_str(reader: &str) -> Self {
quick_xml::de::from_str(reader).unwrap()
}
pub fn save_as<P: AsRef<Path>>(&self, path: P) -> Result<(), OoxmlError> {
let file = File::create(path)?;
self.write(file)
}
pub fn write<W: std::io::Write>(&self, writer: W) -> Result<(), OoxmlError> {
let mut xml = quick_xml::Writer::new(writer);
use quick_xml::events::attributes::Attribute;
use quick_xml::events::*;
xml.write_event(Event::Decl(BytesDecl::new(
b"1.0",
Some(b"UTF-8"),
Some(b"yes"),
)))?;
let mut elem = BytesStart::borrowed_name(SHARED_STRINGS_TAG.as_bytes());
elem.extend_attributes(self.namespaces.to_xml_attributes());
elem.extend_attributes(vec![
Attribute {
key: b"count",
value: format!("{}", self.count).as_bytes().into(),
},
Attribute {
key: b"uniqueCount",
value: format!("{}", self.unique_count).as_bytes().into(),
},
]);
xml.write_event(Event::Start(elem))?;
for si in self.strings.as_ref().unwrap_or(&vec![]) {
let elem = BytesStart::borrowed_name(SHARED_STRING_TAG.as_bytes());
xml.write_event(Event::Start(elem))?;
quick_xml::se::to_writer(xml.inner(), &si.t)?;
let end = BytesEnd::borrowed(SHARED_STRING_TAG.as_bytes());
xml.write_event(Event::End(end))?;
}
let end = BytesEnd::borrowed(SHARED_STRINGS_TAG.as_bytes());
xml.write_event(Event::End(end))?;
Ok(())
}
}
#[test]
#[ignore]
fn test_de() {
const file: &str = "examples/sharedString-missing-t/xl/sharedStrings.xml";
let value = SharedStringsPart::from_xml_file(file).unwrap();
println!("{:?}", value);
let display = format!("{}", value);
println!("{}", display);
}