diff --git a/docx-core/fixtures/hello/docProps/app.xml b/docx-core/fixtures/hello/docProps/app.xml index f819b8e..2c7f60f 100644 --- a/docx-core/fixtures/hello/docProps/app.xml +++ b/docx-core/fixtures/hello/docProps/app.xml @@ -1,2 +1,12 @@ -0LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-311551 \ No newline at end of file + + + 0 + LibreOffice/6.0.7.3$Linux_X86_64 LibreOffice_project/00m0$Build-3 + 1 + 1 + 5 + 5 + 1 + \ No newline at end of file diff --git a/docx-core/fixtures/hello/docProps/core.xml b/docx-core/fixtures/hello/docProps/core.xml index aa2d79a..4e90bed 100644 --- a/docx-core/fixtures/hello/docProps/core.xml +++ b/docx-core/fixtures/hello/docProps/core.xml @@ -1,2 +1,16 @@ -2019-09-13T19:32:17Zja-JP2019-09-13T19:32:34Z1 \ No newline at end of file + + 2019-09-13T19:32:17Z + + + ja-JP + + 2019-09-13T19:32:34Z + 1 + + + \ No newline at end of file diff --git a/docx-core/src/documents/content_types.rs b/docx-core/src/documents/content_types.rs index 5cadba2..0a296f3 100644 --- a/docx-core/src/documents/content_types.rs +++ b/docx-core/src/documents/content_types.rs @@ -9,7 +9,7 @@ impl ContentTypes { pub fn build(&self) -> Vec { let b = XMLBuilder::new(); - b.declaration() + b.declaration(None) .open_types("http://schemas.openxmlformats.org/package/2006/content-types") .add_override( "/_rels/.rels", diff --git a/docx-core/src/documents/doc_props/app.rs b/docx-core/src/documents/doc_props/app.rs new file mode 100644 index 0000000..9ebeb33 --- /dev/null +++ b/docx-core/src/documents/doc_props/app.rs @@ -0,0 +1,113 @@ +use crate::xml_builder::*; + +pub struct AppProps { + config: Option, +} + +pub struct AppPropsConfig { + template: Option<&'static str>, + total_time: Option, + application: Option<&'static str>, + pages: Option, + words: Option, + characters: Option, + characters_with_spaces: Option, + paragraphs: Option, +} + +impl AppProps { + pub fn new(config: Option) -> AppProps { + AppProps { config } + } + + pub(crate) fn build(&self) -> Vec { + let b = XMLBuilder::new(); + let base = b.declaration(Some(true)).open_properties( + "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", + "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + ); + + let convert = |v: usize| format!("{}", v); + let default = || "".to_owned(); + + if let Some(c) = &self.config { + base.template(c.template.map_or_else(|| "", |v| v)) + .total_time(&c.total_time.map_or_else(default, convert)) + .application(c.application.map_or_else(|| "", |v| v)) + .pages(&c.pages.map_or_else(default, convert)) + .words(&c.words.map_or_else(default, convert)) + .characters(&c.characters.map_or_else(default, convert)) + .characters_with_spaces(&c.characters_with_spaces.map_or_else(default, convert)) + .paragraphs(&c.paragraphs.map_or_else(default, convert)) + .close() + .build() + } else { + base.template("") + .total_time("") + .application("") + .pages("") + .words("") + .characters("") + .characters_with_spaces("") + .paragraphs("") + .close() + .build() + } + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use std::str; + + #[test] + fn test_default_doc_props_app_build() { + let c = AppProps::new(None); + let b = c.build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#" + + + + + + + + + +"# + ); + } + + #[test] + fn test_configured_doc_props_app_build() { + let c = AppProps::new(Some(AppPropsConfig { + template: Some("temp"), + total_time: Some(10), + application: Some("Lawgue beta1.0"), + pages: Some(1), + words: Some(20), + characters: Some(10), + characters_with_spaces: Some(22), + paragraphs: Some(30), + })); + let b = c.build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#" + + + 10 + Lawgue beta1.0 + 1 + 20 + 10 + 22 + 30 +"# + ); + } +} diff --git a/docx-core/src/documents/doc_props/mod.rs b/docx-core/src/documents/doc_props/mod.rs new file mode 100644 index 0000000..3b2c4b5 --- /dev/null +++ b/docx-core/src/documents/doc_props/mod.rs @@ -0,0 +1,14 @@ +mod app; + +pub use app::*; + +pub(crate) struct DocProps { + app: AppProps, +} + +impl DocProps { + pub(crate) fn new(appConfig: Option) -> DocProps { + let app = AppProps::new(appConfig); + DocProps { app } + } +} diff --git a/docx-core/src/documents/mod.rs b/docx-core/src/documents/mod.rs index 9627d62..e3c490f 100644 --- a/docx-core/src/documents/mod.rs +++ b/docx-core/src/documents/mod.rs @@ -1,19 +1,27 @@ mod content_types; +mod doc_props; mod rels; mod xml_document; use content_types::*; +use doc_props::*; use rels::*; pub(crate) struct Document { content_type: ContentTypes, rels: Rels, + doc_props: DocProps, } impl Document { pub fn new() -> Document { let content_type = ContentTypes::new(); let rels = Rels::new(); - Document { content_type, rels } + let doc_props = DocProps::new(None /* TODO: */); + Document { + content_type, + rels, + doc_props, + } } } diff --git a/docx-core/src/documents/rels.rs b/docx-core/src/documents/rels.rs index 562cc08..5fa5f0e 100644 --- a/docx-core/src/documents/rels.rs +++ b/docx-core/src/documents/rels.rs @@ -9,7 +9,7 @@ impl Rels { pub fn build(&self) -> Vec { let b = XMLBuilder::new(); - b.declaration() + b.declaration(None) .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships") .relationship( "rId1", diff --git a/docx-core/src/xml_builder/declaration.rs b/docx-core/src/xml_builder/declaration.rs index 84381ff..573005b 100644 --- a/docx-core/src/xml_builder/declaration.rs +++ b/docx-core/src/xml_builder/declaration.rs @@ -3,12 +3,12 @@ use super::XMLBuilder; impl XMLBuilder { // Build XML declaration // i.e. - pub(crate) fn declaration(mut self) -> Self { + pub(crate) fn declaration(mut self, standalone: Option) -> Self { self.writer .write(super::XmlEvent::StartDocument { version: super::XmlVersion::Version10, encoding: Some("UTF-8"), - standalone: None, + standalone, }) .expect("should write to buf"); self @@ -24,7 +24,7 @@ mod tests { #[test] fn test_declaration() { let b = XMLBuilder::new(); - let r = b.declaration().build(); + let r = b.declaration(None).build(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# diff --git a/docx-core/src/xml_builder/macros.rs b/docx-core/src/xml_builder/macros.rs index 90687cd..7c4e56d 100644 --- a/docx-core/src/xml_builder/macros.rs +++ b/docx-core/src/xml_builder/macros.rs @@ -7,6 +7,61 @@ macro_rules! opened_el { self } }; + ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr) => { + pub(crate) fn $name(mut self, arg0: &str, arg1: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0).attr($attr1, arg1)) + .expect("should write to buf"); + self + } + }; +} + +macro_rules! closed_el_with_child { + ($name: ident, $el_name: expr) => { + pub(crate) fn $name(mut self, child: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name)) + .expect("should write to buf"); + self.writer + .write(child) + .expect("should write to buf"); + self.close() + } + }; + ($name: ident, $el_name: expr, $attr0: expr) => { + pub(crate) fn $name(mut self, arg0: &str, child: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0)) + .expect("should write to buf"); + self.writer + .write(child) + .expect("should write to buf"); + self.close() + } + }; + ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr) => { + pub(crate) fn $name(mut self, arg0: &str, arg1: &str, child: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0).attr($attr1, arg1)) + .expect("should write to buf"); + self.writer + .write(child) + .expect("should write to buf"); + self.close() + } + }; + ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr) => { + pub(crate) fn $name(mut self, arg0: &str, arg1: &str, arg2: &str, child: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0).attr($attr1, arg1).attr($attr2, arg2)) + .expect("should write to buf"); + self.writer + .write(child) + .expect("should write to buf"); + self.close() + } + }; } macro_rules! closed_el { diff --git a/docx-core/src/xml_builder/mod.rs b/docx-core/src/xml_builder/mod.rs index 16ca6bc..25839eb 100644 --- a/docx-core/src/xml_builder/mod.rs +++ b/docx-core/src/xml_builder/mod.rs @@ -1,6 +1,7 @@ #[macro_use] mod macros; mod declaration; +mod properties; mod relationship; use xml::common::XmlVersion; diff --git a/docx-core/src/xml_builder/properties.rs b/docx-core/src/xml_builder/properties.rs new file mode 100644 index 0000000..49f6fac --- /dev/null +++ b/docx-core/src/xml_builder/properties.rs @@ -0,0 +1,54 @@ +use super::XMLBuilder; + +impl XMLBuilder { + // Build Properties element + // i.e. + opened_el!(open_properties, "Properties", "xmlns", "xmlns:vt"); + + closed_el_with_child!(template, "Template"); + closed_el_with_child!(total_time, "TotalTime"); + closed_el_with_child!(application, "Application"); + closed_el_with_child!(pages, "Pages"); + closed_el_with_child!(words, "Words"); + closed_el_with_child!(characters, "Characters"); + closed_el_with_child!(characters_with_spaces, "CharactersWithSpaces"); + closed_el_with_child!(paragraphs, "Paragraphs"); +} + +#[cfg(test)] +mod tests { + + use super::XMLBuilder; + use std::str; + + #[test] + fn test_properties() { + let b = XMLBuilder::new(); + let r = b + .open_properties("http://example", "http://example2") + .text("child") + .close() + .build(); + assert_eq!( + str::from_utf8(&r).unwrap(), + r#"child"# + ); + } + + #[test] + fn test_template() { + let b = XMLBuilder::new(); + let r = b.template("0").build(); + assert_eq!(str::from_utf8(&r).unwrap(), r#""#); + } + + #[test] + fn test_application() { + let b = XMLBuilder::new(); + let r = b.template("Lawgue").build(); + assert_eq!( + str::from_utf8(&r).unwrap(), + r#"Lawgue"# + ); + } +}