diff --git a/docx-core/src/documents/build_xml.rs b/docx-core/src/documents/build_xml.rs index 52eb2f9..8f4cd6f 100644 --- a/docx-core/src/documents/build_xml.rs +++ b/docx-core/src/documents/build_xml.rs @@ -1,3 +1,38 @@ +use crate::xml_builder::XMLBuilder; +use std::io::Write; + pub trait BuildXML { - fn build(&self) -> Vec; + /// Write XML to the output stream. + #[doc(hidden)] + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result>; + + #[doc(hidden)] + fn build(&self) -> Vec { + self.build_to(XMLBuilder::new(Vec::new()).into_inner().unwrap()) + .expect("should write to buf") + .into_inner() + } +} + +impl<'a, T: BuildXML> BuildXML for &'a T { + /// Building XML from `&T` is the same as from `T`. + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + (*self).build_to(stream) + } +} + +impl BuildXML for Box { + /// Building XML from `Box` is the same as from `T`. + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + (**self).build_to(stream) + } } diff --git a/docx-core/src/documents/comments.rs b/docx-core/src/documents/comments.rs index b946957..3ab1cd5 100644 --- a/docx-core/src/documents/comments.rs +++ b/docx-core/src/documents/comments.rs @@ -1,6 +1,7 @@ use super::Comment; use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -29,12 +30,16 @@ impl Comments { } impl BuildXML for Comments { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new().declaration(Some(true)).open_comments(); - for c in &self.comments { - b = b.add_child(c) - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_comments()? + .add_children(&self.comments)? + .close()? + .into_inner() } } @@ -51,8 +56,7 @@ mod tests { let b = Comments::new().build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } } diff --git a/docx-core/src/documents/comments_extended.rs b/docx-core/src/documents/comments_extended.rs index 369af00..657fbe2 100644 --- a/docx-core/src/documents/comments_extended.rs +++ b/docx-core/src/documents/comments_extended.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -22,14 +23,15 @@ impl CommentsExtended { } impl BuildXML for CommentsExtended { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b.open_comments_extended(); - - for c in &self.children { - b = b.add_child(c) - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_comments_extended()? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/content_types.rs b/docx-core/src/documents/content_types.rs index 62f97de..aebb7ed 100644 --- a/docx-core/src/documents/content_types.rs +++ b/docx-core/src/documents/content_types.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -use std::io::Read; +use std::io::{Read, Write}; use xml::reader::{EventReader, XmlEvent}; use crate::documents::BuildXML; @@ -153,28 +153,26 @@ impl Default for ContentTypes { } impl BuildXML for ContentTypes { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b - .declaration(None) - .open_types("http://schemas.openxmlformats.org/package/2006/content-types"); - - b = b - .add_default("png", "image/png") - .add_default("jpeg", "image/jpeg") - .add_default("jpg", "image/jpg") - .add_default("bmp", "image/bmp") - .add_default("gif", "image/gif") + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(None)? + .open_types("http://schemas.openxmlformats.org/package/2006/content-types")? + .add_default("png", "image/png")? + .add_default("jpeg", "image/jpeg")? + .add_default("jpg", "image/jpg")? + .add_default("bmp", "image/bmp")? + .add_default("gif", "image/gif")? .add_default( "rels", "application/vnd.openxmlformats-package.relationships+xml", - ) - .add_default("xml", "application/xml"); - - for (k, v) in self.types.iter() { - b = b.add_override(k, v); - } - b.close().build() + )? + .add_default("xml", "application/xml")? + .apply_each(self.types.iter(), |(k, v), b| b.add_override(k, v))? + .close()? + .into_inner() } } @@ -213,8 +211,7 @@ mod tests { #[test] fn test_from_xml() { - let xml = r#" - "#; + let xml = r#""#; let c = ContentTypes::from_xml(xml.as_bytes()).unwrap(); let mut types = BTreeMap::new(); types.insert( diff --git a/docx-core/src/documents/custom_item.rs b/docx-core/src/documents/custom_item.rs index 91580a0..462535b 100644 --- a/docx-core/src/documents/custom_item.rs +++ b/docx-core/src/documents/custom_item.rs @@ -1,7 +1,9 @@ use crate::documents::BuildXML; +use crate::xml_builder::XMLBuilder; use crate::{ParseXmlError, XmlDocument}; use serde::ser::SerializeSeq; use serde::Serialize; +use std::io::Write; use std::str::FromStr; #[derive(Debug, Clone)] @@ -29,8 +31,13 @@ impl Serialize for CustomItem { } impl BuildXML for CustomItem { - fn build(&self) -> Vec { - self.0.to_string().as_bytes().to_vec() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let mut b = XMLBuilder::from(stream); + write!(b.inner_mut()?, "{}", self.0)?; + b.into_inner() } } @@ -44,17 +51,13 @@ mod tests { #[test] fn test_custom_xml() { let c = CustomItem::from_str( - r#" - -"#, + r#""#, ) .unwrap(); assert_eq!( c.0.to_string(), - r#" - -"# + r#""# ); assert_eq!( serde_json::to_string(&c).unwrap(), diff --git a/docx-core/src/documents/custom_item_property.rs b/docx-core/src/documents/custom_item_property.rs index 60f011b..20b7887 100644 --- a/docx-core/src/documents/custom_item_property.rs +++ b/docx-core/src/documents/custom_item_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,16 +16,19 @@ impl CustomItemProperty { } impl BuildXML for CustomItemProperty { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b.declaration(Some(false)); - b = b + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(false))? .open_data_store_item( "http://schemas.openxmlformats.org/officeDocument/2006/customXml", &format!("{{{}}}", self.id), - ) - .open_data_store_schema_refs() - .close(); - b.close().build() + )? + .open_data_store_schema_refs()? + .close()? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/custom_item_rels.rs b/docx-core/src/documents/custom_item_rels.rs index b20d49a..c8c0f7a 100644 --- a/docx-core/src/documents/custom_item_rels.rs +++ b/docx-core/src/documents/custom_item_rels.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -21,21 +22,21 @@ impl CustomItemRels { } impl BuildXML for CustomItemRels { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b - .declaration(Some(true)) - .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships"); - - for id in 0..self.custom_item_count { - let id = id + 1; - b = b.relationship( - &format!("rId{}", id), - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps", - &format!("itemProps{}.xml", id), - ) - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")? + .apply_each(0..self.custom_item_count, |id, b| { + b.relationship( + &format!("rId{}", id + 1), + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps", + &format!("itemProps{}.xml", id + 1), + ) + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/doc_props/app.rs b/docx-core/src/documents/doc_props/app.rs index c46eae9..84f8a0b 100644 --- a/docx-core/src/documents/doc_props/app.rs +++ b/docx-core/src/documents/doc_props/app.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -14,13 +15,18 @@ impl AppProps { } impl BuildXML for AppProps { - 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", - ); - base.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_properties( + "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", + "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + )? + .close()? + .into_inner() } } @@ -38,8 +44,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } } diff --git a/docx-core/src/documents/doc_props/core.rs b/docx-core/src/documents/doc_props/core.rs index fbce26f..4d96dc1 100644 --- a/docx-core/src/documents/doc_props/core.rs +++ b/docx-core/src/documents/doc_props/core.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -56,58 +57,42 @@ impl CorePropsConfig { } impl BuildXML for CoreProps { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let base = b.declaration(Some(true)).open_core_properties( - "http://schemas.openxmlformats.org/package/2006/metadata/core-properties", - "http://purl.org/dc/elements/1.1/", - "http://purl.org/dc/terms/", - "http://purl.org/dc/dcmitype/", - "http://www.w3.org/2001/XMLSchema-instance", - ); - - let convert = |v: usize| format!("{}", v); - let mut base = base + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_core_properties( + "http://schemas.openxmlformats.org/package/2006/metadata/core-properties", + "http://purl.org/dc/elements/1.1/", + "http://purl.org/dc/terms/", + "http://purl.org/dc/dcmitype/", + "http://www.w3.org/2001/XMLSchema-instance", + )? .dcterms_created( "dcterms:W3CDTF", self.config .created - .as_ref() - .map_or_else(|| "1970-01-01T00:00:00Z", |v| v), - ) - .dc_creator( - self.config - .creator - .as_ref() - .map_or_else(|| "unknown", |v| v), - ) - .cp_last_modified_by( - self.config - .last_modified_by - .as_ref() - .map_or_else(|| "unknown", |v| v), - ) + .as_deref() + .unwrap_or("1970-01-01T00:00:00Z"), + )? + .dc_creator(self.config.creator.as_deref().unwrap_or("unknown"))? + .cp_last_modified_by(self.config.last_modified_by.as_deref().unwrap_or("unknown"))? .dcterms_modified( "dcterms:W3CDTF", self.config .modified - .as_ref() - .map_or_else(|| "1970-01-01T00:00:00Z", |v| v), - ) - .cp_revision(&self.config.revision.map_or_else(|| "1".to_owned(), convert)); - if let Some(v) = self.config.description.as_ref() { - base = base.dc_description(v); - } - if let Some(v) = self.config.language.as_ref() { - base = base.dc_language(v); - } - if let Some(v) = self.config.subject.as_ref() { - base = base.dc_subject(v); - } - if let Some(v) = self.config.title.as_ref() { - base = base.dc_title(v); - } - base.close().build() + .as_deref() + .unwrap_or("1970-01-01T00:00:00Z"), + )? + .cp_revision(&self.config.revision.unwrap_or(1).to_string())? + .apply_opt(self.config.description.as_ref(), |v, b| b.dc_description(v))? + .apply_opt(self.config.language.as_ref(), |v, b| b.dc_language(v))? + .apply_opt(self.config.subject.as_ref(), |v, b| b.dc_subject(v))? + .apply_opt(self.config.title.as_ref(), |v, b| b.dc_title(v))? + .close()? + .into_inner() } } @@ -135,14 +120,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - 1970-01-01T00:00:00Z - unknown - unknown - 1970-01-01T00:00:00Z - 1 -"# + r#"1970-01-01T00:00:00Zunknownunknown1970-01-01T00:00:00Z1"# ); } @@ -162,18 +140,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - 2019-01-01 - foo - go - 2019-01-01 - 1 - bar - en - subject - title -"# + r#"2019-01-01foogo2019-01-011barensubjecttitle"# ); } } diff --git a/docx-core/src/documents/doc_props/custom.rs b/docx-core/src/documents/doc_props/custom.rs index 5815de6..a50678f 100644 --- a/docx-core/src/documents/doc_props/custom.rs +++ b/docx-core/src/documents/doc_props/custom.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -21,26 +22,28 @@ impl CustomProps { } impl BuildXML for CustomProps { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut base = b.declaration(Some(true)).open_custom_properties( - "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties", - "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", - ); - - for (i, (key, item)) in self.properties.iter().enumerate() { - base = base - .open_property( + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_custom_properties( + "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties", + "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + )? + .apply_each(self.properties.iter().enumerate(), |(i, (key, item)), b| { + b.open_property( "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", - // I can not found spec about this id. - // It is invalid if pid started by 1.... + // I can not find spec about this id. + // It is invalid if pid starts from 1... &format!("{}", i + 2), key, - ) - .lpwstr(item) + )? + .lpwstr(item)? .close() - } - - base.close().build() + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/document.rs b/docx-core/src/documents/document.rs index 95660f0..7a1967b 100644 --- a/docx-core/src/documents/document.rs +++ b/docx-core/src/documents/document.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -236,31 +237,37 @@ impl Document { } impl BuildXML for DocumentChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - DocumentChild::Paragraph(v) => v.build(), - DocumentChild::Table(v) => v.build(), - DocumentChild::BookmarkStart(v) => v.build(), - DocumentChild::BookmarkEnd(v) => v.build(), - DocumentChild::CommentStart(v) => v.build(), - DocumentChild::CommentEnd(v) => v.build(), - DocumentChild::StructuredDataTag(v) => v.build(), - DocumentChild::TableOfContents(v) => v.build(), + DocumentChild::Paragraph(v) => v.build_to(stream), + DocumentChild::Table(v) => v.build_to(stream), + DocumentChild::BookmarkStart(v) => v.build_to(stream), + DocumentChild::BookmarkEnd(v) => v.build_to(stream), + DocumentChild::CommentStart(v) => v.build_to(stream), + DocumentChild::CommentEnd(v) => v.build_to(stream), + DocumentChild::StructuredDataTag(v) => v.build_to(stream), + DocumentChild::TableOfContents(v) => v.build_to(stream), } } } impl BuildXML for Document { - fn build(&self) -> Vec { - XMLBuilder::new() - .declaration(Some(true)) - .open_document() - .open_body() - .add_children(&self.children) - .add_child(&self.section_property) - .close() - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_document()? + .open_body()? + .add_children(&self.children)? + .add_child(&self.section_property)? + .close()? + .close()? + .into_inner() } } @@ -280,11 +287,7 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - Hello - -"# + r#"Hello"# ); } @@ -294,12 +297,7 @@ mod tests { let b = Document::new().add_table_of_contents(toc).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - TOC \o "1-3" - - -"# + r#"TOC \o "1-3""# ); } @@ -311,11 +309,7 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - Hello - -"# + r#"Hello"# ); } } diff --git a/docx-core/src/documents/document_rels.rs b/docx-core/src/documents/document_rels.rs index 2eda540..c6f643a 100644 --- a/docx-core/src/documents/document_rels.rs +++ b/docx-core/src/documents/document_rels.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -45,97 +46,91 @@ impl DocumentRels { } impl BuildXML for DocumentRels { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b - .declaration(None) - .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships") + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(None)? + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")? .relationship( "rId1", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml", - ) + )? .relationship( "rId2", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable", "fontTable.xml", - ) + )? .relationship( "rId3", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", "settings.xml", - ) + )? .relationship( "rId5", "http://schemas.microsoft.com/office/2011/relationships/commentsExtended", "commentsExtended.xml", - ); - - if self.has_comments { - b = b.relationship( - "rId6", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", - "comments.xml", - ) - } - - if self.has_numberings { - b = b.relationship( - "rId7", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", - "numbering.xml", - ) - } - - if self.has_footnotes { - b = b.relationship( - "rId8", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", - "footnotes.xml", - ) - } - - for i in 0..self.header_count { - b = b.relationship( - &create_header_rid(i + 1), - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", - &format!("header{}.xml", i + 1), - ) - } - - for i in 0..self.footer_count { - b = b.relationship( - &create_footer_rid(i + 1), - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer", - &format!("footer{}.xml", i + 1), - ) - } - - for i in 0..self.custom_xml_count { - b = b.relationship( - &format!("rId{}", i + 8), - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml", - &format!("../customXml/item{}.xml", i + 1), - ) - } - - for (id, path) in self.images.iter() { - b = b.relationship( - id, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - path, - ) - } - - for (id, path, r#type) in self.hyperlinks.iter() { - b = b.relationship_with_mode( - id, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", - path, - r#type, - ) - } - - b.close().build() + )? + .apply_if(self.has_comments, |b| { + b.relationship( + "rId6", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", + "comments.xml", + ) + })? + .apply_if(self.has_numberings, |b| { + b.relationship( + "rId7", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", + "numbering.xml", + ) + })? + .apply_if(self.has_footnotes, |b| { + b.relationship( + "rId8", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", + "footnotes.xml", + ) + })? + .apply_each(0..self.header_count, |i, b| { + b.relationship( + &create_header_rid(i + 1), + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", + &format!("header{}.xml", i + 1), + ) + })? + .apply_each(0..self.footer_count, |i, b| { + b.relationship( + &create_footer_rid(i + 1), + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer", + &format!("footer{}.xml", i + 1), + ) + })? + .apply_each(0..self.custom_xml_count, |i, b| { + b.relationship( + &format!("rId{}", i + 8), + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml", + &format!("../customXml/item{}.xml", i + 1), + ) + })? + .apply_each(self.images.iter(), |(id, path), b| { + b.relationship( + id, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + path, + ) + })? + .apply_each(self.hyperlinks.iter(), |(id, path, r#type), b| { + b.relationship_with_mode( + id, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", + path, + r#type, + ) + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/a_graphic.rs b/docx-core/src/documents/elements/a_graphic.rs index f50f2d3..251974f 100644 --- a/docx-core/src/documents/elements/a_graphic.rs +++ b/docx-core/src/documents/elements/a_graphic.rs @@ -1,5 +1,6 @@ use super::*; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -22,13 +23,15 @@ impl AGraphic { } impl BuildXML for AGraphic { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_graphic("http://schemas.openxmlformats.org/drawingml/2006/main"); - for child in &self.children { - b = b.add_child(child); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_graphic("http://schemas.openxmlformats.org/drawingml/2006/main")? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/a_graphic_data.rs b/docx-core/src/documents/elements/a_graphic_data.rs index 0a15cd0..d49a297 100644 --- a/docx-core/src/documents/elements/a_graphic_data.rs +++ b/docx-core/src/documents/elements/a_graphic_data.rs @@ -1,6 +1,7 @@ use super::*; use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use std::str::FromStr; use crate::documents::BuildXML; @@ -95,15 +96,17 @@ impl AGraphicData { } impl BuildXML for AGraphicData { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_graphic_data(self.data_type.to_uri()); - for c in &self.children { - match c { - GraphicDataChild::Shape(t) => b = b.add_child(t), - GraphicDataChild::Pic(t) => b = b.add_child(t), - } - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_graphic_data(self.data_type.to_uri())? + .apply_each(&self.children, |ch, b| match ch { + GraphicDataChild::Shape(t) => b.add_child(t), + GraphicDataChild::Pic(t) => b.add_child(t), + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/abstract_numbering.rs b/docx-core/src/documents/elements/abstract_numbering.rs index 6d9b675..8cef260 100644 --- a/docx-core/src/documents/elements/abstract_numbering.rs +++ b/docx-core/src/documents/elements/abstract_numbering.rs @@ -1,5 +1,6 @@ use crate::documents::{BuildXML, Level}; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -39,14 +40,15 @@ impl AbstractNumbering { } impl BuildXML for AbstractNumbering { - fn build(&self) -> Vec { - let id = format!("{}", self.id); - let mut b = XMLBuilder::new(); - b = b.open_abstract_num(&id); - for l in &self.levels { - b = b.add_child(l); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_abstract_num(&self.id.to_string())? + .add_children(&self.levels)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/adjust_right_ind.rs b/docx-core/src/documents/elements/adjust_right_ind.rs index 0718c19..014f6ae 100644 --- a/docx-core/src/documents/elements/adjust_right_ind.rs +++ b/docx-core/src/documents/elements/adjust_right_ind.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -13,9 +14,13 @@ impl AdjustRightInd { } impl BuildXML for AdjustRightInd { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.adjust_right_ind(self.0).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .adjust_right_ind(self.0)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/based_on.rs b/docx-core/src/documents/elements/based_on.rs index dbba3e7..8242b2b 100644 --- a/docx-core/src/documents/elements/based_on.rs +++ b/docx-core/src/documents/elements/based_on.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -27,9 +28,11 @@ impl Serialize for BasedOn { } impl BuildXML for BasedOn { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.based_on(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).based_on(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/bold.rs b/docx-core/src/documents/elements/bold.rs index 4049452..aa52934 100644 --- a/docx-core/src/documents/elements/bold.rs +++ b/docx-core/src/documents/elements/bold.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -35,8 +36,10 @@ impl Serialize for Bold { } impl BuildXML for Bold { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.b().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).b()?.into_inner() } } diff --git a/docx-core/src/documents/elements/bold_cs.rs b/docx-core/src/documents/elements/bold_cs.rs index 82a5c82..ce32e39 100644 --- a/docx-core/src/documents/elements/bold_cs.rs +++ b/docx-core/src/documents/elements/bold_cs.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -34,8 +35,10 @@ impl Serialize for BoldCs { } impl BuildXML for BoldCs { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.b_cs().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).b_cs()?.into_inner() } } diff --git a/docx-core/src/documents/elements/bookmark_end.rs b/docx-core/src/documents/elements/bookmark_end.rs index 44f6ee5..9dd13df 100644 --- a/docx-core/src/documents/elements/bookmark_end.rs +++ b/docx-core/src/documents/elements/bookmark_end.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,13 @@ impl BookmarkEnd { } impl BuildXML for BookmarkEnd { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.bookmark_end(&format!("{}", self.id)).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .bookmark_end(&self.id.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/bookmark_start.rs b/docx-core/src/documents/elements/bookmark_start.rs index 41e1a35..e82dba8 100644 --- a/docx-core/src/documents/elements/bookmark_start.rs +++ b/docx-core/src/documents/elements/bookmark_start.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -19,10 +20,13 @@ impl BookmarkStart { } impl BuildXML for BookmarkStart { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.bookmark_start(&format!("{}", self.id), &self.name) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .bookmark_start(&self.id.to_string(), &self.name)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/br.rs b/docx-core/src/documents/elements/br.rs index ee7a5ad..dc4ab26 100644 --- a/docx-core/src/documents/elements/br.rs +++ b/docx-core/src/documents/elements/br.rs @@ -1,5 +1,6 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::Deserialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -17,9 +18,13 @@ impl Break { } impl BuildXML for Break { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.br(&self.break_type.to_string()).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .br(&self.break_type.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/cant_split.rs b/docx-core/src/documents/elements/cant_split.rs index 04133a4..52387a5 100644 --- a/docx-core/src/documents/elements/cant_split.rs +++ b/docx-core/src/documents/elements/cant_split.rs @@ -1,13 +1,16 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::{xml_builder::XMLBuilder, BuildXML}; #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct CantSplit {} impl BuildXML for CantSplit { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.cant_split().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).cant_split()?.into_inner() } } diff --git a/docx-core/src/documents/elements/caps.rs b/docx-core/src/documents/elements/caps.rs index cbdce33..37be22c 100644 --- a/docx-core/src/documents/elements/caps.rs +++ b/docx-core/src/documents/elements/caps.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::{xml_builder::XMLBuilder, BuildXML}; @@ -37,8 +38,12 @@ impl Serialize for Caps { } impl BuildXML for Caps { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.caps(&self.val.to_string()).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .caps(&self.val.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/cell_margins.rs b/docx-core/src/documents/elements/cell_margins.rs index 0e9dbc4..7be9f52 100644 --- a/docx-core/src/documents/elements/cell_margins.rs +++ b/docx-core/src/documents/elements/cell_margins.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -66,25 +67,26 @@ impl CellMargins { } impl BuildXML for CellMargins { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new().open_cell_margins(); - - if let Some(ref top) = self.top { - b = b.margin_top(top.val as i32, top.width_type); - } - - if let Some(ref left) = self.left { - b = b.margin_left(left.val as i32, left.width_type); - } - - if let Some(ref bottom) = self.bottom { - b = b.margin_bottom(bottom.val as i32, bottom.width_type); - } - - if let Some(ref right) = self.right { - b = b.margin_right(right.val as i32, right.width_type); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_cell_margins()? + .apply_opt(self.top.as_ref(), |top, b| { + b.margin_top(top.val as i32, top.width_type) + })? + .apply_opt(self.left.as_ref(), |left, b| { + b.margin_left(left.val as i32, left.width_type) + })? + .apply_opt(self.bottom.as_ref(), |bottom, b| { + b.margin_bottom(bottom.val as i32, bottom.width_type) + })? + .apply_opt(self.right.as_ref(), |right, b| { + b.margin_right(right.val as i32, right.width_type) + })? + .close()? + .into_inner() } } @@ -101,9 +103,7 @@ mod tests { let b = CellMargins::new().margin_top(10, WidthType::Dxa).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/character_spacing.rs b/docx-core/src/documents/elements/character_spacing.rs index 4e159cf..acba6b4 100644 --- a/docx-core/src/documents/elements/character_spacing.rs +++ b/docx-core/src/documents/elements/character_spacing.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::*; @@ -16,9 +17,11 @@ impl CharacterSpacing { } impl BuildXML for CharacterSpacing { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.spacing(self.value).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).spacing(self.value)?.into_inner() } } diff --git a/docx-core/src/documents/elements/color.rs b/docx-core/src/documents/elements/color.rs index 9c4543a..c00d73a 100644 --- a/docx-core/src/documents/elements/color.rs +++ b/docx-core/src/documents/elements/color.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,8 +16,11 @@ impl Color { } impl BuildXML for Color { - fn build(&self) -> Vec { - XMLBuilder::new().color(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).color(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/comment.rs b/docx-core/src/documents/elements/comment.rs index dcd11a4..ae96a77 100644 --- a/docx-core/src/documents/elements/comment.rs +++ b/docx-core/src/documents/elements/comment.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::xml_builder::*; @@ -93,21 +94,27 @@ impl Comment { } impl BuildXML for CommentChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - CommentChild::Paragraph(v) => v.build(), - CommentChild::Table(v) => v.build(), + CommentChild::Paragraph(v) => v.build_to(stream), + CommentChild::Table(v) => v.build_to(stream), } } } impl BuildXML for Comment { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_comment(&format!("{}", self.id), &self.author, &self.date, "") - .add_children(&self.children) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_comment(&self.id.to_string(), &self.author, &self.date, "")? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/comment_extended.rs b/docx-core/src/documents/elements/comment_extended.rs index 113586a..ab7c0bc 100644 --- a/docx-core/src/documents/elements/comment_extended.rs +++ b/docx-core/src/documents/elements/comment_extended.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -32,10 +33,13 @@ impl CommentExtended { } impl BuildXML for CommentExtended { - fn build(&self) -> Vec { - XMLBuilder::new() - .comment_extended(&self.paragraph_id, self.done, &self.parent_paragraph_id) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .comment_extended(&self.paragraph_id, self.done, &self.parent_paragraph_id)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/comment_range_end.rs b/docx-core/src/documents/elements/comment_range_end.rs index 5313f78..f8883c8 100644 --- a/docx-core/src/documents/elements/comment_range_end.rs +++ b/docx-core/src/documents/elements/comment_range_end.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,17 +16,20 @@ impl CommentRangeEnd { } impl BuildXML for CommentRangeEnd { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_run() - .open_run_property() - .close() - .close() - .comment_range_end(&format!("{}", self.id)) - .open_run() - .comment_reference(&format!("{}", self.id)) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_run()? + .open_run_property()? + .close()? + .close()? + .comment_range_end(&format!("{}", self.id))? + .open_run()? + .comment_reference(&format!("{}", self.id))? + .close()? + .into_inner() } } @@ -43,13 +47,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/comment_range_start.rs b/docx-core/src/documents/elements/comment_range_start.rs index 1faeb3e..4cd1b51 100644 --- a/docx-core/src/documents/elements/comment_range_start.rs +++ b/docx-core/src/documents/elements/comment_range_start.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::Comment; use crate::documents::BuildXML; @@ -32,16 +33,13 @@ impl CommentRangeStart { } impl BuildXML for CommentRangeStart { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.comment_range_start(&format!("{}", self.id)).build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.comment_range_start(&format!("{}", self.id)).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .comment_range_start(&self.id.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/data_binding.rs b/docx-core/src/documents/elements/data_binding.rs index 82ab173..b64df63 100644 --- a/docx-core/src/documents/elements/data_binding.rs +++ b/docx-core/src/documents/elements/data_binding.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::xml_builder::*; @@ -32,14 +33,17 @@ impl DataBinding { } impl BuildXML for DataBinding { - fn build(&self) -> Vec { - XMLBuilder::new() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) .data_binding( self.xpath.as_ref(), self.prefix_mappings.as_ref(), self.store_item_id.as_ref(), - ) - .build() + )? + .into_inner() } } diff --git a/docx-core/src/documents/elements/default_tab_stop.rs b/docx-core/src/documents/elements/default_tab_stop.rs index a588573..f327802 100644 --- a/docx-core/src/documents/elements/default_tab_stop.rs +++ b/docx-core/src/documents/elements/default_tab_stop.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::{Serialize, Serializer}; @@ -15,9 +16,13 @@ impl DefaultTabStop { } impl BuildXML for DefaultTabStop { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.default_tab_stop(self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .default_tab_stop(self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/delete.rs b/docx-core/src/documents/elements/delete.rs index a863219..48f2c14 100644 --- a/docx-core/src/documents/elements/delete.rs +++ b/docx-core/src/documents/elements/delete.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::xml_builder::*; use crate::{documents::*, escape}; @@ -97,18 +98,20 @@ impl Delete { impl HistoryId for Delete {} impl BuildXML for Delete { - #[allow(clippy::needless_borrow)] - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let id = self.generate(); - let mut b = XMLBuilder::new().open_delete(&id, &self.author, &self.date); - for c in &self.children { - match c { - DeleteChild::Run(t) => b = b.add_child(t), - DeleteChild::CommentStart(c) => b = b.add_child(c), - DeleteChild::CommentEnd(c) => b = b.add_child(c), - } - } - b.close().build() + XMLBuilder::from(stream) + .open_delete(&id, &self.author, &self.date)? + .apply_each(&self.children, |ch, b| match ch { + DeleteChild::Run(t) => b.add_child(t), + DeleteChild::CommentStart(c) => b.add_child(&c), + DeleteChild::CommentEnd(c) => b.add_child(c), + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/delete_instr_text.rs b/docx-core/src/documents/elements/delete_instr_text.rs index 408e8a6..5de4a63 100644 --- a/docx-core/src/documents/elements/delete_instr_text.rs +++ b/docx-core/src/documents/elements/delete_instr_text.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::xml_builder::*; @@ -14,25 +15,21 @@ pub enum DeleteInstrText { } impl BuildXML for DeleteInstrText { - fn build(&self) -> Vec { - let instr = match self { - DeleteInstrText::TOC(toc) => toc.build(), - DeleteInstrText::TC(tc) => tc.build(), - DeleteInstrText::PAGEREF(page_ref) => page_ref.build(), - DeleteInstrText::HYPERLINK(_link) => todo!(), - DeleteInstrText::Unsupported(s) => s.as_bytes().to_vec(), - }; - XMLBuilder::new() - .open_delete_instr_text() - .add_bytes(&instr) - .close() - .build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - self.as_ref().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_delete_instr_text()? + .apply(|b| match self { + DeleteInstrText::TOC(toc) => b.add_child(toc), + DeleteInstrText::TC(tc) => b.add_child(tc), + DeleteInstrText::PAGEREF(page_ref) => b.add_child(page_ref), + DeleteInstrText::HYPERLINK(_link) => todo!(), + DeleteInstrText::Unsupported(s) => b.plain_text(s), + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/delete_text.rs b/docx-core/src/documents/elements/delete_text.rs index 949c42f..baa9fbb 100644 --- a/docx-core/src/documents/elements/delete_text.rs +++ b/docx-core/src/documents/elements/delete_text.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -28,8 +29,13 @@ impl DeleteText { } impl BuildXML for DeleteText { - fn build(&self) -> Vec { - XMLBuilder::new().delete_text(&self.text, true).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .delete_text(&self.text, true)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/doc_defaults.rs b/docx-core/src/documents/elements/doc_defaults.rs index 34e02eb..8a1251a 100644 --- a/docx-core/src/documents/elements/doc_defaults.rs +++ b/docx-core/src/documents/elements/doc_defaults.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::{documents::BuildXML, RunProperty}; use crate::{xml_builder::*, LineSpacing, ParagraphProperty, ParagraphPropertyDefault}; @@ -61,13 +62,16 @@ impl Default for DocDefaults { } impl BuildXML for DocDefaults { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_doc_defaults() - .add_child(&self.run_property_default) - .add_child(&self.paragraph_property_default) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_doc_defaults()? + .add_child(&self.run_property_default)? + .add_child(&self.paragraph_property_default)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/doc_grid.rs b/docx-core/src/documents/elements/doc_grid.rs index dd4c3e5..c0e97a4 100644 --- a/docx-core/src/documents/elements/doc_grid.rs +++ b/docx-core/src/documents/elements/doc_grid.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -52,9 +53,12 @@ impl Default for DocGrid { } impl BuildXML for DocGrid { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.doc_grid(&self.grid_type, self.line_pitch, self.char_space) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .doc_grid(&self.grid_type, self.line_pitch, self.char_space)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/doc_id.rs b/docx-core/src/documents/elements/doc_id.rs index 7022dfb..7d54b03 100644 --- a/docx-core/src/documents/elements/doc_id.rs +++ b/docx-core/src/documents/elements/doc_id.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -24,9 +25,11 @@ impl Serialize for DocId { } impl BuildXML for DocId { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let id = format!("{{{}}}", self.id); - b.doc_id(&id).build() + XMLBuilder::from(stream).doc_id(&id)?.into_inner() } } diff --git a/docx-core/src/documents/elements/doc_var.rs b/docx-core/src/documents/elements/doc_var.rs index 190df30..4fd8211 100644 --- a/docx-core/src/documents/elements/doc_var.rs +++ b/docx-core/src/documents/elements/doc_var.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -19,8 +20,12 @@ impl DocVar { } impl BuildXML for DocVar { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.doc_var(&self.name, &self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .doc_var(&self.name, &self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/drawing.rs b/docx-core/src/documents/elements/drawing.rs index 2af72c2..c883473 100644 --- a/docx-core/src/documents/elements/drawing.rs +++ b/docx-core/src/documents/elements/drawing.rs @@ -1,5 +1,6 @@ use super::*; use serde::{ser::*, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -55,16 +56,13 @@ impl Drawing { } } -impl BuildXML for Box { - fn build(&self) -> Vec { - self.as_ref().build() - } -} - impl BuildXML for Drawing { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_drawing(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let b = XMLBuilder::from(stream); + let mut b = b.open_drawing()?; match &self.data { Some(DrawingData::Pic(p)) => { @@ -74,7 +72,7 @@ impl BuildXML for Drawing { &format!("{}", p.dist_b), &format!("{}", p.dist_l), &format!("{}", p.dist_r), - ) + )? } else { b = b .open_wp_anchor( @@ -88,32 +86,32 @@ impl BuildXML for Drawing { "0", if p.layout_in_cell { "1" } else { "0" }, &format!("{}", p.relative_height), - ) + )? .simple_pos( &format!("{}", p.simple_pos_x), &format!("{}", p.simple_pos_y), - ) - .open_position_h(&format!("{}", p.relative_from_h)); + )? + .open_position_h(&format!("{}", p.relative_from_h))?; match p.position_h { DrawingPosition::Offset(x) => { let x = format!("{}", x as u32); - b = b.pos_offset(&x).close(); + b = b.pos_offset(&x)?.close()?; } DrawingPosition::Align(x) => { - b = b.align(&x.to_string()).close(); + b = b.align(&x.to_string())?.close()?; } } - b = b.open_position_v(&format!("{}", p.relative_from_v)); + b = b.open_position_v(&format!("{}", p.relative_from_v))?; match p.position_v { DrawingPosition::Offset(y) => { let y = format!("{}", y as u32); - b = b.pos_offset(&y).close(); + b = b.pos_offset(&y)?.close()?; } DrawingPosition::Align(a) => { - b = b.align(&a.to_string()).close(); + b = b.align(&a.to_string())?.close()?; } } } @@ -123,33 +121,35 @@ impl BuildXML for Drawing { b = b // Please see 20.4.2.7 extent (Drawing Object Size) // One inch equates to 914400 EMUs and a centimeter is 360000 - .wp_extent(&w, &h) - .wp_effect_extent("0", "0", "0", "0"); + .wp_extent(&w, &h)? + .wp_effect_extent("0", "0", "0", "0")?; if p.allow_overlap { - b = b.wrap_none(); + b = b.wrap_none()?; } else if p.position_type == DrawingPositionType::Anchor { - b = b.wrap_square("bothSides"); + b = b.wrap_square("bothSides")?; } b = b - .wp_doc_pr("1", "Figure") - .open_wp_c_nv_graphic_frame_pr() + .wp_doc_pr("1", "Figure")? + .open_wp_c_nv_graphic_frame_pr()? .a_graphic_frame_locks( "http://schemas.openxmlformats.org/drawingml/2006/main", "1", - ) - .close() - .open_a_graphic("http://schemas.openxmlformats.org/drawingml/2006/main") - .open_a_graphic_data("http://schemas.openxmlformats.org/drawingml/2006/picture") - .add_child(&p.clone()) - .close() - .close(); + )? + .close()? + .open_a_graphic("http://schemas.openxmlformats.org/drawingml/2006/main")? + .open_a_graphic_data( + "http://schemas.openxmlformats.org/drawingml/2006/picture", + )? + .add_child(&p.clone())? + .close()? + .close()?; } Some(DrawingData::TextBox(_t)) => unimplemented!("TODO: Support textBox writer"), None => { unimplemented!() } } - b.close().close().build() + b.close()?.close()?.into_inner() } } @@ -167,42 +167,7 @@ mod tests { let d = Drawing::new().pic(pic).build(); assert_eq!( str::from_utf8(&d).unwrap(), - r#" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"# + r#""# ); } @@ -212,43 +177,7 @@ mod tests { let d = Drawing::new().pic(pic).build(); assert_eq!( str::from_utf8(&d).unwrap(), - r#" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"# + r#""# ); } @@ -261,50 +190,7 @@ mod tests { let d = Drawing::new().pic(pic).build(); assert_eq!( str::from_utf8(&d).unwrap(), - r#" - - - - right - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"# + r#"right0"# ); } @@ -319,50 +205,7 @@ mod tests { let d = Drawing::new().pic(pic).build(); assert_eq!( str::from_utf8(&d).unwrap(), - r#" - - - - 2857500 - - - 3810000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"# + r#"28575003810000"# ); } } diff --git a/docx-core/src/documents/elements/fld_char.rs b/docx-core/src/documents/elements/fld_char.rs index b7b100e..ac6421e 100644 --- a/docx-core/src/documents/elements/fld_char.rs +++ b/docx-core/src/documents/elements/fld_char.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::types::*; @@ -28,13 +29,16 @@ impl FieldChar { } impl BuildXML for FieldChar { - fn build(&self) -> Vec { - XMLBuilder::new() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) .field_character( &format!("{}", self.field_char_type), &format!("{}", &self.dirty), - ) - .build() + )? + .into_inner() } } diff --git a/docx-core/src/documents/elements/font.rs b/docx-core/src/documents/elements/font.rs index 8a0e607..623e7c0 100644 --- a/docx-core/src/documents/elements/font.rs +++ b/docx-core/src/documents/elements/font.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; +use std::io::Write; #[derive(Debug)] pub struct Font<'a> { @@ -22,14 +23,17 @@ impl<'a> Font<'a> { } impl<'a> BuildXML for Font<'a> { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_font(self.name) - .charset(self.charset) - .family(self.family) - .pitch(&self.pitch.to_string()) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_font(self.name)? + .charset(self.charset)? + .family(self.family)? + .pitch(&self.pitch.to_string())? + .close()? + .into_inner() } } @@ -47,11 +51,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/footer_reference.rs b/docx-core/src/documents/elements/footer_reference.rs index 5dbc155..0ad2551 100644 --- a/docx-core/src/documents/elements/footer_reference.rs +++ b/docx-core/src/documents/elements/footer_reference.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -20,9 +21,12 @@ impl FooterReference { } impl BuildXML for FooterReference { - fn build(&self) -> Vec { - XMLBuilder::new() - .footer_reference(&self.footer_type, &self.id) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .footer_reference(&self.footer_type, &self.id)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/footnote.rs b/docx-core/src/documents/elements/footnote.rs index 5d17b64..96b7a30 100644 --- a/docx-core/src/documents/elements/footnote.rs +++ b/docx-core/src/documents/elements/footnote.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::xml_builder::*; @@ -47,7 +48,10 @@ impl From<&FootnoteReference> for Footnote { } impl BuildXML for Footnote { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { // To ensure docx compatible XML serialization for footnotes, we default to an empty paragraph. let mut footnote = self.clone(); if self.content == vec![] { @@ -55,11 +59,11 @@ impl BuildXML for Footnote { footnote.add_content(Paragraph::new()); } - XMLBuilder::new() - .open_footnote(&format!("{}", self.id)) - .add_children(&footnote.content) - .close() - .build() + XMLBuilder::from(stream) + .open_footnote(&format!("{}", self.id))? + .add_children(&footnote.content)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/footnote_reference.rs b/docx-core/src/documents/elements/footnote_reference.rs index 0d0189e..ad66d9f 100644 --- a/docx-core/src/documents/elements/footnote_reference.rs +++ b/docx-core/src/documents/elements/footnote_reference.rs @@ -1,4 +1,5 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::{xml_builder::*, Footnote, Paragraph}; @@ -35,8 +36,13 @@ impl From for FootnoteReference { } impl BuildXML for FootnoteReference { - fn build(&self) -> Vec { - XMLBuilder::new().footnote_reference(self.id).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .footnote_reference(self.id)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/frame_property.rs b/docx-core/src/documents/elements/frame_property.rs index 514316f..5df5283 100644 --- a/docx-core/src/documents/elements/frame_property.rs +++ b/docx-core/src/documents/elements/frame_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -120,9 +121,11 @@ impl FrameProperty { } impl BuildXML for FrameProperty { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.frame_property(self).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).frame_property(self)?.into_inner() } } diff --git a/docx-core/src/documents/elements/grid_span.rs b/docx-core/src/documents/elements/grid_span.rs index 325a78b..5fcea92 100644 --- a/docx-core/src/documents/elements/grid_span.rs +++ b/docx-core/src/documents/elements/grid_span.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,8 +16,11 @@ impl GridSpan { } impl BuildXML for GridSpan { - fn build(&self) -> Vec { - XMLBuilder::new().grid_span(self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).grid_span(self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/header_reference.rs b/docx-core/src/documents/elements/header_reference.rs index 9599e66..6e0e6cc 100644 --- a/docx-core/src/documents/elements/header_reference.rs +++ b/docx-core/src/documents/elements/header_reference.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -29,9 +30,12 @@ impl HeaderReference { } impl BuildXML for HeaderReference { - fn build(&self) -> Vec { - XMLBuilder::new() - .header_reference(&self.header_type, &self.id) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .header_reference(&self.header_type, &self.id)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/highlight.rs b/docx-core/src/documents/elements/highlight.rs index fcbc233..25799c4 100644 --- a/docx-core/src/documents/elements/highlight.rs +++ b/docx-core/src/documents/elements/highlight.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,8 +16,11 @@ impl Highlight { } impl BuildXML for Highlight { - fn build(&self) -> Vec { - XMLBuilder::new().highlight(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).highlight(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/hyperlink.rs b/docx-core/src/documents/elements/hyperlink.rs index 499d5b2..456a6fe 100644 --- a/docx-core/src/documents/elements/hyperlink.rs +++ b/docx-core/src/documents/elements/hyperlink.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -98,25 +99,26 @@ impl Hyperlink { } impl BuildXML for Hyperlink { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - match self.link { - HyperlinkData::Anchor { ref anchor } => { - b = b.open_hyperlink( + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .apply(|b| match self.link { + HyperlinkData::Anchor { ref anchor } => b.open_hyperlink( None, Some(anchor.clone()).as_ref(), Some(self.history.unwrap_or(1)), - ) - } - HyperlinkData::External { ref rid, .. } => { - b = b.open_hyperlink( + ), + HyperlinkData::External { ref rid, .. } => b.open_hyperlink( Some(rid.clone()).as_ref(), None, Some(self.history.unwrap_or(1)), - ) - } - }; - b.add_children(&self.children).close().build() + ), + })? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/indent.rs b/docx-core/src/documents/elements/indent.rs index 6f12fde..cba91d2 100644 --- a/docx-core/src/documents/elements/indent.rs +++ b/docx-core/src/documents/elements/indent.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -51,15 +52,18 @@ impl Indent { } impl BuildXML for Indent { - fn build(&self) -> Vec { - XMLBuilder::new() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) .indent( self.start, self.special_indent, self.end.unwrap_or_default(), self.start_chars, - ) - .build() + )? + .into_inner() } } diff --git a/docx-core/src/documents/elements/indent_level.rs b/docx-core/src/documents/elements/indent_level.rs index 704bc50..9c8da28 100644 --- a/docx-core/src/documents/elements/indent_level.rs +++ b/docx-core/src/documents/elements/indent_level.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; #[derive(Debug, Clone, PartialEq)] pub struct IndentLevel { @@ -13,9 +14,13 @@ impl IndentLevel { } impl BuildXML for IndentLevel { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.indent_level(self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .indent_level(self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/insert.rs b/docx-core/src/documents/elements/insert.rs index 1d85113..f23fc38 100644 --- a/docx-core/src/documents/elements/insert.rs +++ b/docx-core/src/documents/elements/insert.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; @@ -15,12 +16,15 @@ pub enum InsertChild { } impl BuildXML for InsertChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - InsertChild::Run(v) => v.build(), - InsertChild::Delete(v) => v.build(), - InsertChild::CommentStart(v) => v.build(), - InsertChild::CommentEnd(v) => v.build(), + InsertChild::Run(v) => v.build_to(stream), + InsertChild::Delete(v) => v.build_to(stream), + InsertChild::CommentStart(v) => v.build_to(stream), + InsertChild::CommentEnd(v) => v.build_to(stream), } } } @@ -140,13 +144,15 @@ impl Insert { impl HistoryId for Insert {} impl BuildXML for Insert { - #[allow(clippy::needless_borrow)] - fn build(&self) -> Vec { - XMLBuilder::new() - .open_insert(&self.generate(), &self.author, &self.date) - .add_children(&self.children) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_insert(&self.generate(), &self.author, &self.date)? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/instr_num_pages.rs b/docx-core/src/documents/elements/instr_num_pages.rs index bca1c96..00049cc 100644 --- a/docx-core/src/documents/elements/instr_num_pages.rs +++ b/docx-core/src/documents/elements/instr_num_pages.rs @@ -1,6 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; +use crate::xml_builder::XMLBuilder; #[derive(Serialize, Debug, Clone, PartialEq, Default)] #[serde(rename_all = "camelCase")] @@ -13,8 +15,12 @@ impl InstrNUMPAGES { } impl BuildXML for InstrNUMPAGES { - fn build(&self) -> Vec { - let instr = "NUMPAGES".to_owned(); - instr.into() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .plain_text("NUMPAGES")? + .into_inner() } } diff --git a/docx-core/src/documents/elements/instr_page.rs b/docx-core/src/documents/elements/instr_page.rs index 1e45f6f..541f5a1 100644 --- a/docx-core/src/documents/elements/instr_page.rs +++ b/docx-core/src/documents/elements/instr_page.rs @@ -1,6 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; +use crate::xml_builder::XMLBuilder; #[derive(Serialize, Debug, Clone, PartialEq, Default)] #[serde(rename_all = "camelCase")] @@ -13,8 +15,10 @@ impl InstrPAGE { } impl BuildXML for InstrPAGE { - fn build(&self) -> Vec { - let instr = "PAGE".to_owned(); - instr.into() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).plain_text("PAGE")?.into_inner() } } diff --git a/docx-core/src/documents/elements/instr_pageref.rs b/docx-core/src/documents/elements/instr_pageref.rs index 4f8a9bb..4aa881f 100644 --- a/docx-core/src/documents/elements/instr_pageref.rs +++ b/docx-core/src/documents/elements/instr_pageref.rs @@ -1,6 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; +use crate::xml_builder::XMLBuilder; // https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_PAGEREFPAGEREF_topic_ID0EHXK1.html #[derive(Serialize, Debug, Clone, PartialEq, Default)] @@ -31,18 +33,16 @@ impl InstrPAGEREF { } impl BuildXML for InstrPAGEREF { - fn build(&self) -> Vec { - let mut instr = format!("PAGEREF {}", self.page_ref); - - if self.relative_position { - instr = format!("{} \\p", instr); - } - - if self.hyperlink { - instr = format!("{} \\h", instr); - } - - instr.into() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .plain_text("PAGEREF ")? + .plain_text(&self.page_ref)? + .apply_if(self.relative_position, |b| b.plain_text(" \\p"))? + .apply_if(self.hyperlink, |b| b.plain_text(" \\h"))? + .into_inner() } } @@ -78,9 +78,6 @@ mod tests { #[test] fn test_page_ref() { let b = InstrPAGEREF::new("_Toc00000000").hyperlink().build(); - assert_eq!( - str::from_utf8(&b).unwrap(), - r#"PAGEREF _Toc00000000 \h"# - ); + assert_eq!(str::from_utf8(&b).unwrap(), r#"PAGEREF _Toc00000000 \h"#); } } diff --git a/docx-core/src/documents/elements/instr_tc.rs b/docx-core/src/documents/elements/instr_tc.rs index d1bfcdd..a124ee2 100644 --- a/docx-core/src/documents/elements/instr_tc.rs +++ b/docx-core/src/documents/elements/instr_tc.rs @@ -1,6 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; +use crate::xml_builder::XMLBuilder; // https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TCTC_topic_ID0EU2N1.html #[derive(Serialize, Debug, Clone, PartialEq, Default)] @@ -39,22 +41,28 @@ impl InstrTC { } impl BuildXML for InstrTC { - fn build(&self) -> Vec { - let mut instr = format!("TC {}", self.text); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let mut b = XMLBuilder::from(stream); + let raw = b.inner_mut()?; + + write!(raw, "TC {}", self.text)?; if let Some(ref t) = self.item_type_identifier { - instr = format!("{} \\f {}", instr, t); + write!(raw, " \\f {}", t)?; } if let Some(level) = self.level { - instr = format!("{} \\l {}", instr, level); + write!(raw, " \\l {}", level)?; } if self.omits_page_number { - instr = format!("{} \\n", instr); + write!(raw, " \\n")?; } - instr.into() + b.into_inner() } } diff --git a/docx-core/src/documents/elements/instr_text.rs b/docx-core/src/documents/elements/instr_text.rs index f690ee9..62e39ad 100644 --- a/docx-core/src/documents/elements/instr_text.rs +++ b/docx-core/src/documents/elements/instr_text.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::xml_builder::*; @@ -16,21 +17,23 @@ pub enum InstrText { } impl BuildXML for Box { - fn build(&self) -> Vec { - let instr = match self.as_ref() { - InstrText::TOC(toc) => toc.build(), - InstrText::TC(tc) => tc.build(), - InstrText::PAGEREF(page_ref) => page_ref.build(), - InstrText::PAGE(page) => page.build(), - InstrText::NUMPAGES(page) => page.build(), - InstrText::HYPERLINK(_link) => todo!(), - InstrText::Unsupported(s) => s.as_bytes().to_vec(), - }; - XMLBuilder::new() - .open_instr_text() - .add_bytes(&instr) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_instr_text()? + .apply(|b| match self.as_ref() { + InstrText::TOC(toc) => b.add_child(toc), + InstrText::TC(tc) => b.add_child(tc), + InstrText::PAGEREF(page_ref) => b.add_child(page_ref), + InstrText::PAGE(page) => b.add_child(page), + InstrText::NUMPAGES(page) => b.add_child(page), + InstrText::HYPERLINK(_link) => todo!(), + InstrText::Unsupported(s) => b.plain_text(s), + })? + .close()? + .into_inner() } } @@ -86,6 +89,7 @@ impl Serialize for InstrText { } } +#[allow(unused_allocation)] #[cfg(test)] mod tests { diff --git a/docx-core/src/documents/elements/instr_toc.rs b/docx-core/src/documents/elements/instr_toc.rs index 6ae8c1f..2bcaa48 100644 --- a/docx-core/src/documents/elements/instr_toc.rs +++ b/docx-core/src/documents/elements/instr_toc.rs @@ -1,6 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; +use crate::xml_builder::XMLBuilder; #[derive(Serialize, Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "wasm", derive(ts_rs::TS))] @@ -159,57 +161,63 @@ impl InstrToC { } impl BuildXML for InstrToC { - fn build(&self) -> Vec { - let mut instr = "TOC".to_string(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let mut b = XMLBuilder::from(stream); + let raw = b.inner_mut()?; + + write!(raw, "TOC")?; // \a if let Some(ref t) = self.caption_label { - instr = format!("{} \\a "{}"", instr, t); + write!(raw, " \\a "{}"", t)?; } // \b if let Some(ref t) = self.entry_bookmark_name { - instr = format!("{} \\b "{}"", instr, t); + write!(raw, " \\b "{}"", t)?; } // \c if let Some(ref t) = self.caption_label_including_numbers { - instr = format!("{} \\c "{}"", instr, t); + write!(raw, " \\c "{}"", t)?; } // \d if let Some(ref t) = self.sequence_and_page_numbers_separator { - instr = format!("{} \\d "{}"", instr, t); + write!(raw, " \\d "{}"", t)?; } // \f if let Some(ref t) = self.tc_field_identifier { - instr = format!("{} \\f "{}"", instr, t); + write!(raw, " \\f "{}"", t)?; } // \l if let Some(range) = self.tc_field_level_range { - instr = format!("{} \\l "{}-{}"", instr, range.0, range.1); + write!(raw, " \\l "{}-{}"", range.0, range.1)?; } // \n if let Some(range) = self.omit_page_numbers_level_range { - instr = format!("{} \\n "{}-{}"", instr, range.0, range.1); + write!(raw, " \\n "{}-{}"", range.0, range.1)?; } // \o if let Some(range) = self.heading_styles_range { - instr = format!("{} \\o "{}-{}"", instr, range.0, range.1); + write!(raw, " \\o "{}-{}"", range.0, range.1)?; } // \p if let Some(ref t) = self.entry_and_page_number_separator { - instr = format!("{} \\p "{}"", instr, t); + write!(raw, " \\p "{}"", t)?; } // \s if let Some(ref t) = self.seq_field_identifier_for_prefix { - instr = format!("{} \\s "{}"", instr, t); + write!(raw, " \\s "{}"", t)?; } // \t @@ -220,35 +228,35 @@ impl BuildXML for InstrToC { .map(|s| format!("{},{}", (s.0).0, (s.0).1)) .collect::>() .join(","); - instr = format!("{} \\t "{}"", instr, s); + write!(raw, " \\t "{}"", s)?; } // \h if self.hyperlink { - instr = format!("{} \\h", instr); + write!(raw, " \\h")?; } // \u if self.use_applied_paragraph_line_level { - instr = format!("{} \\u", instr); + write!(raw, " \\u")?; } // \w if self.preserve_tab { - instr = format!("{} \\w", instr); + write!(raw, " \\w")?; } // \x if self.preserve_new_line { - instr = format!("{} \\x", instr); + write!(raw, " \\x")?; } // \z if self.hide_tab_and_page_numbers_in_webview { - instr = format!("{} \\z", instr); + write!(raw, " \\z")?; } - instr.into() + b.into_inner() } } diff --git a/docx-core/src/documents/elements/is_lgl.rs b/docx-core/src/documents/elements/is_lgl.rs index efdd9cc..ef640ac 100644 --- a/docx-core/src/documents/elements/is_lgl.rs +++ b/docx-core/src/documents/elements/is_lgl.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -13,9 +14,11 @@ impl IsLgl { } impl BuildXML for IsLgl { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.is_lgl().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).is_lgl()?.into_inner() } } diff --git a/docx-core/src/documents/elements/italic.rs b/docx-core/src/documents/elements/italic.rs index 597ce27..3d4de4a 100644 --- a/docx-core/src/documents/elements/italic.rs +++ b/docx-core/src/documents/elements/italic.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -35,8 +36,10 @@ impl Serialize for Italic { } impl BuildXML for Italic { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.i().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).i()?.into_inner() } } diff --git a/docx-core/src/documents/elements/italic_cs.rs b/docx-core/src/documents/elements/italic_cs.rs index edc78ee..eaabfbc 100644 --- a/docx-core/src/documents/elements/italic_cs.rs +++ b/docx-core/src/documents/elements/italic_cs.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -35,8 +36,10 @@ impl Serialize for ItalicCs { } impl BuildXML for ItalicCs { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.i_cs().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).i_cs()?.into_inner() } } diff --git a/docx-core/src/documents/elements/justification.rs b/docx-core/src/documents/elements/justification.rs index 61e4cd4..955f85c 100644 --- a/docx-core/src/documents/elements/justification.rs +++ b/docx-core/src/documents/elements/justification.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -23,9 +24,13 @@ impl Justification { } impl BuildXML for Justification { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.justification(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .justification(&self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/level.rs b/docx-core/src/documents/elements/level.rs index 2b4f437..6774411 100644 --- a/docx-core/src/documents/elements/level.rs +++ b/docx-core/src/documents/elements/level.rs @@ -1,6 +1,7 @@ use crate::documents::*; use crate::types::*; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -125,24 +126,26 @@ impl Level { } impl BuildXML for Level { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new() - .open_level(&format!("{}", self.level)) - .add_child(&self.start) - .add_child(&self.format) - .add_child(&self.text) - .add_child(&self.jc) - .add_child(&self.paragraph_property) - .add_child(&self.run_property) - .add_optional_child(&self.pstyle) - .add_optional_child(&self.level_restart) - .add_optional_child(&self.is_lgl); - - if self.suffix != LevelSuffixType::Tab { - b = b.suffix(&self.suffix.to_string()); - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_level(&format!("{}", self.level))? + .add_child(&self.start)? + .add_child(&self.format)? + .add_child(&self.text)? + .add_child(&self.jc)? + .add_child(&self.paragraph_property)? + .add_child(&self.run_property)? + .add_optional_child(&self.pstyle)? + .add_optional_child(&self.level_restart)? + .add_optional_child(&self.is_lgl)? + .apply_if(self.suffix != LevelSuffixType::Tab, |b| { + b.suffix(&self.suffix.to_string()) + })? + .close()? + .into_inner() } } @@ -199,8 +202,7 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } #[test] diff --git a/docx-core/src/documents/elements/level_jc.rs b/docx-core/src/documents/elements/level_jc.rs index 104e021..bdec82e 100644 --- a/docx-core/src/documents/elements/level_jc.rs +++ b/docx-core/src/documents/elements/level_jc.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,13 @@ impl LevelJc { } impl BuildXML for LevelJc { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.level_justification(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .level_justification(&self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/level_override.rs b/docx-core/src/documents/elements/level_override.rs index fc451f0..d57c61e 100644 --- a/docx-core/src/documents/elements/level_override.rs +++ b/docx-core/src/documents/elements/level_override.rs @@ -1,4 +1,5 @@ use super::*; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -38,17 +39,18 @@ impl LevelOverride { } impl BuildXML for LevelOverride { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b.open_level_override(&format!("{}", self.level)); - - b = b.add_optional_child(&self.override_level); - - if let Some(start) = self.override_start { - b = b.start_override(&format!("{}", start)); - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_level_override(&format!("{}", self.level))? + .add_optional_child(&self.override_level)? + .apply_opt(self.override_start, |start, b| { + b.start_override(&format!("{}", start)) + })? + .close()? + .into_inner() } } @@ -66,9 +68,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - -"# + r#""# ); } diff --git a/docx-core/src/documents/elements/level_restart.rs b/docx-core/src/documents/elements/level_restart.rs index e45b57f..7d0eec6 100644 --- a/docx-core/src/documents/elements/level_restart.rs +++ b/docx-core/src/documents/elements/level_restart.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,10 +16,13 @@ impl LevelRestart { } impl BuildXML for LevelRestart { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let v = format!("{}", &self.val); - b.level_restart(&v).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .level_restart(&format!("{}", &self.val))? + .into_inner() } } diff --git a/docx-core/src/documents/elements/level_text.rs b/docx-core/src/documents/elements/level_text.rs index dc8416d..1b5871a 100644 --- a/docx-core/src/documents/elements/level_text.rs +++ b/docx-core/src/documents/elements/level_text.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,11 @@ impl LevelText { } impl BuildXML for LevelText { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.level_text(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).level_text(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/line_spacing.rs b/docx-core/src/documents/elements/line_spacing.rs index e95e2ac..6775e6c 100644 --- a/docx-core/src/documents/elements/line_spacing.rs +++ b/docx-core/src/documents/elements/line_spacing.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use crate::line_spacing_type::LineSpacingType; use serde::*; @@ -58,17 +59,20 @@ impl LineSpacing { } impl BuildXML for LineSpacing { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.line_spacing( - self.before, - self.after, - self.line, - self.before_lines, - self.after_lines, - self.line_rule, - ) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .line_spacing( + self.before, + self.after, + self.line, + self.before_lines, + self.after_lines, + self.line_rule, + )? + .into_inner() } } diff --git a/docx-core/src/documents/elements/link.rs b/docx-core/src/documents/elements/link.rs index 73be4f5..69b70cc 100644 --- a/docx-core/src/documents/elements/link.rs +++ b/docx-core/src/documents/elements/link.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -27,8 +28,10 @@ impl Serialize for Link { } impl BuildXML for Link { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.link(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).link(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/mc_fallback.rs b/docx-core/src/documents/elements/mc_fallback.rs index 76700b4..1fd805a 100644 --- a/docx-core/src/documents/elements/mc_fallback.rs +++ b/docx-core/src/documents/elements/mc_fallback.rs @@ -1,7 +1,8 @@ use crate::documents::BuildXML; use serde::Serialize; +use std::io::Write; -#[derive(Debug, Clone, Serialize, PartialEq, Default)] +#[derive(Debug, Default, Clone, PartialEq, Serialize)] pub struct McFallback {} impl McFallback { @@ -11,8 +12,11 @@ impl McFallback { } impl BuildXML for McFallback { - fn build(&self) -> Vec { - // Ignore for now - vec![] + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + // Ignore for now + Ok(stream) } } diff --git a/docx-core/src/documents/elements/name.rs b/docx-core/src/documents/elements/name.rs index 6517837..5474148 100644 --- a/docx-core/src/documents/elements/name.rs +++ b/docx-core/src/documents/elements/name.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use std::str::FromStr; @@ -36,9 +37,11 @@ impl Name { } impl BuildXML for Name { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.name(&self.name).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).name(&self.name)?.into_inner() } } diff --git a/docx-core/src/documents/elements/next.rs b/docx-core/src/documents/elements/next.rs index 5fb4bc2..333d91c 100644 --- a/docx-core/src/documents/elements/next.rs +++ b/docx-core/src/documents/elements/next.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -24,9 +25,11 @@ impl Serialize for Next { } impl BuildXML for Next { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.next(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).next(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/num_pages.rs b/docx-core/src/documents/elements/num_pages.rs index e3832ff..33343f4 100644 --- a/docx-core/src/documents/elements/num_pages.rs +++ b/docx-core/src/documents/elements/num_pages.rs @@ -1,8 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::types::*; -use crate::xml_builder::*; #[derive(Serialize, Debug, Clone, PartialEq)] pub struct NumPages { @@ -21,29 +21,20 @@ impl NumPages { pub fn new() -> Self { Self::default() } +} - fn inner_build(&self) -> Vec { - let b = XMLBuilder::new(); - let r = Run::new() +impl BuildXML for NumPages { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + Run::new() .add_field_char(FieldCharType::Begin, false) .add_instr_text(InstrText::NUMPAGES(self.instr.clone())) .add_field_char(FieldCharType::Separate, false) .add_text("1") - .add_field_char(FieldCharType::End, false); - - b.add_child(&r).build() - } -} - -impl BuildXML for NumPages { - fn build(&self) -> Vec { - self.inner_build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - self.inner_build() + .add_field_char(FieldCharType::End, false) + .build_to(stream) } } diff --git a/docx-core/src/documents/elements/number_format.rs b/docx-core/src/documents/elements/number_format.rs index 096c933..c6c77d2 100644 --- a/docx-core/src/documents/elements/number_format.rs +++ b/docx-core/src/documents/elements/number_format.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,13 @@ impl NumberFormat { } impl BuildXML for NumberFormat { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.number_format(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .number_format(&self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/numbering.rs b/docx-core/src/documents/elements/numbering.rs index 105b59c..b5a269a 100644 --- a/docx-core/src/documents/elements/numbering.rs +++ b/docx-core/src/documents/elements/numbering.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use super::*; use serde::Serialize; @@ -33,15 +34,18 @@ impl Numbering { } impl BuildXML for Numbering { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let id = format!("{}", self.id); let abs_id = format!("{}", self.abstract_num_id); - b.open_num(&id) - .abstract_num_id(&abs_id) - .add_children(&self.level_overrides) - .close() - .build() + XMLBuilder::from(stream) + .open_num(&id)? + .abstract_num_id(&abs_id)? + .add_children(&self.level_overrides)? + .close()? + .into_inner() } } @@ -59,9 +63,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - -"# + r#""# ); } #[test] @@ -74,12 +76,7 @@ mod tests { let b = c.overrides(overrides).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - -"# + r#""# ); } diff --git a/docx-core/src/documents/elements/numbering_id.rs b/docx-core/src/documents/elements/numbering_id.rs index ec39959..8cf8f41 100644 --- a/docx-core/src/documents/elements/numbering_id.rs +++ b/docx-core/src/documents/elements/numbering_id.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -15,9 +16,11 @@ impl NumberingId { } impl BuildXML for NumberingId { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.num_id(self.id).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).num_id(self.id)?.into_inner() } } diff --git a/docx-core/src/documents/elements/numbering_property.rs b/docx-core/src/documents/elements/numbering_property.rs index b765ddb..db10b9f 100644 --- a/docx-core/src/documents/elements/numbering_property.rs +++ b/docx-core/src/documents/elements/numbering_property.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::{IndentLevel, NumberingId}; use crate::documents::BuildXML; @@ -29,13 +30,16 @@ impl NumberingProperty { } impl BuildXML for NumberingProperty { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_numbering_property() - .add_optional_child(&self.id) - .add_optional_child(&self.level) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_numbering_property()? + .add_optional_child(&self.id)? + .add_optional_child(&self.level)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/outline_lvl.rs b/docx-core/src/documents/elements/outline_lvl.rs index 9d3590c..722f6f5 100644 --- a/docx-core/src/documents/elements/outline_lvl.rs +++ b/docx-core/src/documents/elements/outline_lvl.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::*; @@ -16,11 +17,14 @@ impl OutlineLvl { } impl BuildXML for OutlineLvl { - fn build(&self) -> Vec { - XMLBuilder::new() - .outline_lvl(self.v) - // .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .outline_lvl(self.v)? + // .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/page_margin.rs b/docx-core/src/documents/elements/page_margin.rs index 0f76f2f..ce595d6 100644 --- a/docx-core/src/documents/elements/page_margin.rs +++ b/docx-core/src/documents/elements/page_margin.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::types::PageMargin; use crate::xml_builder::*; +use std::io::Write; // These values were based on microsoft office word2019 windows edition. // @@ -53,8 +54,11 @@ impl PageMargin { } impl BuildXML for PageMargin { - fn build(&self) -> Vec { - XMLBuilder::new() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) .page_margin( &format!("{}", self.top), &format!("{}", self.right), @@ -63,8 +67,8 @@ impl BuildXML for PageMargin { &format!("{}", self.header), &format!("{}", self.footer), &format!("{}", self.gutter), - ) - .build() + )? + .into_inner() } } diff --git a/docx-core/src/documents/elements/page_num.rs b/docx-core/src/documents/elements/page_num.rs index 89f69eb..508e621 100644 --- a/docx-core/src/documents/elements/page_num.rs +++ b/docx-core/src/documents/elements/page_num.rs @@ -1,8 +1,8 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::types::*; -use crate::xml_builder::*; #[derive(Serialize, Debug, Clone, PartialEq)] pub struct PageNum { @@ -21,29 +21,20 @@ impl PageNum { pub fn new() -> Self { Self::default() } +} - fn inner_build(&self) -> Vec { - let b = XMLBuilder::new(); - let r = Run::new() +impl BuildXML for PageNum { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + Run::new() .add_field_char(FieldCharType::Begin, false) .add_instr_text(InstrText::PAGE(self.instr.clone())) .add_field_char(FieldCharType::Separate, false) .add_text("1") - .add_field_char(FieldCharType::End, false); - - b.add_child(&r).build() - } -} - -impl BuildXML for PageNum { - fn build(&self) -> Vec { - self.inner_build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - self.inner_build() + .add_field_char(FieldCharType::End, false) + .build_to(stream) } } diff --git a/docx-core/src/documents/elements/page_num_type.rs b/docx-core/src/documents/elements/page_num_type.rs index 23d52a2..5eb3a9e 100644 --- a/docx-core/src/documents/elements/page_num_type.rs +++ b/docx-core/src/documents/elements/page_num_type.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::xml_builder::*; use serde::Serialize; +use std::io::Write; #[derive(Debug, Clone, PartialEq, Serialize, Default)] #[cfg_attr(feature = "wasm", derive(ts_rs::TS))] @@ -34,9 +35,12 @@ impl PageNumType { } impl BuildXML for PageNumType { - fn build(&self) -> Vec { - XMLBuilder::new() - .page_num_type(self.start, self.chap_style.clone()) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .page_num_type(self.start, self.chap_style.clone())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/page_size.rs b/docx-core/src/documents/elements/page_size.rs index c0bafe0..94d1668 100644 --- a/docx-core/src/documents/elements/page_size.rs +++ b/docx-core/src/documents/elements/page_size.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -54,20 +55,19 @@ impl PageSize { } impl BuildXML for PageSize { - fn build(&self) -> Vec { - if let Some(orient) = self.orient { - XMLBuilder::new() - .page_size_with_orient( - &format!("{}", self.w), - &format!("{}", self.h), - &orient.to_string(), - ) - .build() - } else { - XMLBuilder::new() - .page_size(&format!("{}", self.w), &format!("{}", self.h)) - .build() - } + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let w = format!("{}", self.w); + let h = format!("{}", self.h); + + XMLBuilder::from(stream) + .apply(|b| match self.orient { + None => b.page_size(&w, &h), + Some(orient) => b.page_size_with_orient(&w, &h, &orient.to_string()), + })? + .into_inner() } } diff --git a/docx-core/src/documents/elements/paragraph.rs b/docx-core/src/documents/elements/paragraph.rs index 84cdf90..f22bc8f 100644 --- a/docx-core/src/documents/elements/paragraph.rs +++ b/docx-core/src/documents/elements/paragraph.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -42,19 +43,22 @@ pub enum ParagraphChild { } impl BuildXML for ParagraphChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - ParagraphChild::Run(v) => v.build(), - ParagraphChild::Insert(v) => v.build(), - ParagraphChild::Delete(v) => v.build(), - ParagraphChild::Hyperlink(v) => v.build(), - ParagraphChild::BookmarkStart(v) => v.build(), - ParagraphChild::BookmarkEnd(v) => v.build(), - ParagraphChild::CommentStart(v) => v.build(), - ParagraphChild::CommentEnd(v) => v.build(), - ParagraphChild::StructuredDataTag(v) => v.build(), - ParagraphChild::PageNum(v) => v.build(), - ParagraphChild::NumPages(v) => v.build(), + ParagraphChild::Run(v) => v.build_to(stream), + ParagraphChild::Insert(v) => v.build_to(stream), + ParagraphChild::Delete(v) => v.build_to(stream), + ParagraphChild::Hyperlink(v) => v.build_to(stream), + ParagraphChild::BookmarkStart(v) => v.build_to(stream), + ParagraphChild::BookmarkEnd(v) => v.build_to(stream), + ParagraphChild::CommentStart(v) => v.build_to(stream), + ParagraphChild::CommentEnd(v) => v.build_to(stream), + ParagraphChild::StructuredDataTag(v) => v.build_to(stream), + ParagraphChild::PageNum(v) => v.build_to(stream), + ParagraphChild::NumPages(v) => v.build_to(stream), } } } @@ -493,19 +497,16 @@ impl Paragraph { } impl BuildXML for Paragraph { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_paragraph(&self.id) - .add_child(&self.property) - .add_children(&self.children) - .close() - .build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - Paragraph::build(self) + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_paragraph(&self.id)? + .add_child(&self.property)? + .add_children(&self.children)? + .close()? + .into_inner() } } @@ -550,13 +551,7 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#"Hello - - - - - -"# + r#"Hello"# ); } diff --git a/docx-core/src/documents/elements/paragraph_borders.rs b/docx-core/src/documents/elements/paragraph_borders.rs index 493cbb3..f41ddba 100644 --- a/docx-core/src/documents/elements/paragraph_borders.rs +++ b/docx-core/src/documents/elements/paragraph_borders.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -81,22 +82,24 @@ impl ParagraphBorder { } impl BuildXML for ParagraphBorder { - fn build(&self) -> Vec { - let base = XMLBuilder::new(); - let base = { - let val = self.val.to_string(); - let space = self.space.to_string(); - let size = self.size.to_string(); - match self.position { - ParagraphBorderPosition::Top => base.paragraph_border_top(&val, &space, &size, &self.color), - ParagraphBorderPosition::Left => base.paragraph_border_left(&val, &space, &size, &self.color), - ParagraphBorderPosition::Bottom => base.paragraph_border_bottom(&val, &space, &size, &self.color), - ParagraphBorderPosition::Right => base.paragraph_border_right(&val, &space, &size, &self.color), - ParagraphBorderPosition::Between => base.paragraph_border_between(&val, &space, &size, &self.color), - ParagraphBorderPosition::Bar => base.paragraph_border_bar(&val, &space, &size, &self.color), - } + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let val = self.val.to_string(); + let space = self.space.to_string(); + let size = self.size.to_string(); + let func = match self.position { + ParagraphBorderPosition::Top => XMLBuilder::paragraph_border_top, + ParagraphBorderPosition::Left => XMLBuilder::paragraph_border_left, + ParagraphBorderPosition::Bottom => XMLBuilder::paragraph_border_bottom, + ParagraphBorderPosition::Right => XMLBuilder::paragraph_border_right, + ParagraphBorderPosition::Between => XMLBuilder::paragraph_border_between, + ParagraphBorderPosition::Bar => XMLBuilder::paragraph_border_bar, }; - base.build() + XMLBuilder::from(stream) + .apply(|b| func(b, &val, &space, &size, &self.color))? + .into_inner() } } @@ -111,7 +114,6 @@ pub struct ParagraphBorders { bar: Option, } - impl Default for ParagraphBorders { fn default() -> Self { ParagraphBorders { @@ -168,26 +170,32 @@ impl ParagraphBorders { pub fn clear_all(mut self) -> Self { self.left = Some(ParagraphBorder::new(ParagraphBorderPosition::Left).val(BorderType::Nil)); - self.right = Some(ParagraphBorder::new(ParagraphBorderPosition::Right).val(BorderType::Nil)); + self.right = + Some(ParagraphBorder::new(ParagraphBorderPosition::Right).val(BorderType::Nil)); self.top = Some(ParagraphBorder::new(ParagraphBorderPosition::Top).val(BorderType::Nil)); - self.bottom = Some(ParagraphBorder::new(ParagraphBorderPosition::Bottom).val(BorderType::Nil)); - self.between = Some(ParagraphBorder::new(ParagraphBorderPosition::Between).val(BorderType::Nil)); + self.bottom = + Some(ParagraphBorder::new(ParagraphBorderPosition::Bottom).val(BorderType::Nil)); + self.between = + Some(ParagraphBorder::new(ParagraphBorderPosition::Between).val(BorderType::Nil)); self.bar = Some(ParagraphBorder::new(ParagraphBorderPosition::Bar).val(BorderType::Nil)); self } } impl BuildXML for ParagraphBorders { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_paragraph_borders() - .add_optional_child(&self.left) - .add_optional_child(&self.right) - .add_optional_child(&self.top) - .add_optional_child(&self.bottom) - .add_optional_child(&self.between) - .add_optional_child(&self.bar) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_paragraph_borders()? + .add_optional_child(&self.left)? + .add_optional_child(&self.right)? + .add_optional_child(&self.top)? + .add_optional_child(&self.bottom)? + .add_optional_child(&self.between)? + .add_optional_child(&self.bar)? + .close()? + .into_inner() } -} \ No newline at end of file +} diff --git a/docx-core/src/documents/elements/paragraph_property.rs b/docx-core/src/documents/elements/paragraph_property.rs index 846bdad..ed1792e 100644 --- a/docx-core/src/documents/elements/paragraph_property.rs +++ b/docx-core/src/documents/elements/paragraph_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -201,68 +202,39 @@ impl ParagraphProperty { } } -fn inner_build(p: &ParagraphProperty) -> Vec { - let mut b = XMLBuilder::new() - .open_paragraph_property() - .add_child(&p.run_property) - .add_optional_child(&p.style) - .add_optional_child(&p.numbering_property) - .add_optional_child(&p.frame_property) - .add_optional_child(&p.alignment) - .add_optional_child(&p.indent) - .add_optional_child(&p.line_spacing) - .add_optional_child(&p.outline_lvl) - .add_optional_child(&p.paragraph_property_change) - .add_optional_child(&p.borders) - .add_optional_child(&p.text_alignment) - .add_optional_child(&p.adjust_right_ind); - - if let Some(v) = p.snap_to_grid { - b = b.snap_to_grid(v) - } - - if let Some(v) = p.keep_next { - if v { - b = b.keep_next() - } - } - - if let Some(v) = p.keep_lines { - if v { - b = b.keep_lines() - } - } - - if let Some(v) = p.page_break_before { - if v { - b = b.page_break_before() - } - } - - if let Some(v) = p.widow_control { - b = b.widow_control(if v { "1" } else { "0" }) - } - - if !p.tabs.is_empty() { - b = b.open_tabs(); - for t in p.tabs.iter() { - b = b.tab(t.val, t.leader, t.pos); - } - b = b.close(); - } - - b.close().build() -} - impl BuildXML for ParagraphProperty { - fn build(&self) -> Vec { - inner_build(self) - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - inner_build(self) + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_paragraph_property()? + .add_child(&self.run_property)? + .add_optional_child(&self.style)? + .add_optional_child(&self.numbering_property)? + .add_optional_child(&self.frame_property)? + .add_optional_child(&self.alignment)? + .add_optional_child(&self.indent)? + .add_optional_child(&self.line_spacing)? + .add_optional_child(&self.outline_lvl)? + .add_optional_child(&self.paragraph_property_change)? + .add_optional_child(&self.borders)? + .add_optional_child(&self.text_alignment)? + .add_optional_child(&self.adjust_right_ind)? + .apply_opt(self.snap_to_grid, |v, b| b.snap_to_grid(v))? + .apply_if(self.keep_next, |b| b.keep_next())? + .apply_if(self.keep_lines, |b| b.keep_lines())? + .apply_if(self.page_break_before, |b| b.page_break_before())? + .apply_opt(self.widow_control, |flag, b| { + b.widow_control(if flag { "1" } else { "0" }) + })? + .apply_if(!self.tabs.is_empty(), |b| { + b.open_tabs()? + .apply_each(&self.tabs, |tab, b| b.tab(tab.val, tab.leader, tab.pos))? + .close() + })? + .close()? + .into_inner() } } @@ -307,8 +279,7 @@ mod tests { let b = c.keep_next(true).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } diff --git a/docx-core/src/documents/elements/paragraph_property_change.rs b/docx-core/src/documents/elements/paragraph_property_change.rs index a3221b3..d6c3d3a 100644 --- a/docx-core/src/documents/elements/paragraph_property_change.rs +++ b/docx-core/src/documents/elements/paragraph_property_change.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::escape; @@ -17,7 +18,7 @@ impl Default for ParagraphPropertyChange { Self { author: "unnamed".to_owned(), date: "1970-01-01T00:00:00Z".to_owned(), - property: Box::new(ParagraphProperty::default()), + property: Default::default(), } } } @@ -48,14 +49,16 @@ impl ParagraphPropertyChange { impl ParagraphPropertyChangeId for ParagraphPropertyChange {} impl BuildXML for ParagraphPropertyChange { - #[allow(clippy::needless_borrow)] - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let id = self.generate(); - XMLBuilder::new() - .open_paragraph_property_change(&id, &self.author, &self.date) - .add_child(&self.property) - .close() - .build() + XMLBuilder::from(stream) + .open_paragraph_property_change(&id, &self.author, &self.date)? + .add_child(&self.property)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/paragraph_property_default.rs b/docx-core/src/documents/elements/paragraph_property_default.rs index 4d027fe..5f7dce4 100644 --- a/docx-core/src/documents/elements/paragraph_property_default.rs +++ b/docx-core/src/documents/elements/paragraph_property_default.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -34,12 +35,15 @@ impl Default for ParagraphPropertyDefault { } impl BuildXML for ParagraphPropertyDefault { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_paragraph_property_default() - .add_child(&self.paragraph_property) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_paragraph_property_default()? + .add_child(&self.paragraph_property)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/paragraph_style.rs b/docx-core/src/documents/elements/paragraph_style.rs index 49c06ae..5604fc7 100644 --- a/docx-core/src/documents/elements/paragraph_style.rs +++ b/docx-core/src/documents/elements/paragraph_style.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -36,8 +37,13 @@ impl ParagraphStyle { } impl BuildXML for ParagraphStyle { - fn build(&self) -> Vec { - XMLBuilder::new().paragraph_style(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .paragraph_style(&self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/pic.rs b/docx-core/src/documents/elements/pic.rs index 5a331e5..7490729 100644 --- a/docx-core/src/documents/elements/pic.rs +++ b/docx-core/src/documents/elements/pic.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::types::*; @@ -13,7 +14,7 @@ pub struct Pic { // For writer only #[serde(skip_serializing_if = "Vec::is_empty")] pub image: Vec, - // unit is emu + // (width, height). unit is emu pub size: (u32, u32), pub position_type: DrawingPositionType, /// Specifies that this object shall be positioned using the positioning information in the @@ -203,35 +204,36 @@ impl Pic { } impl BuildXML for Pic { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let w = format!("{}", self.size.0); - let h = format!("{}", self.size.1); - b.open_pic("http://schemas.openxmlformats.org/drawingml/2006/picture") - .open_pic_nv_pic_pr() - .pic_c_nv_pr("0", "") - .open_pic_c_nv_pic_pr() - .a_pic_locks("1", "1") - .close() - .close() - .open_blip_fill() - .a_blip(&self.id) - .a_src_rect() - .open_a_stretch() - .a_fill_rect() - .close() - .close() - .open_pic_sp_pr("auto") - .open_a_xfrm_with_rot(&format!("{}", (self.rot as u32) * 60 * 1000)) - .a_off("0", "0") - .a_ext(&w, &h) - .close() - .open_a_prst_geom("rect") - .a_av_lst() - .close() - .close() - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_pic("http://schemas.openxmlformats.org/drawingml/2006/picture")? + .open_pic_nv_pic_pr()? + .pic_c_nv_pr("0", "")? + .open_pic_c_nv_pic_pr()? + .a_pic_locks("1", "1")? + .close()? + .close()? + .open_blip_fill()? + .a_blip(&self.id)? + .a_src_rect()? + .open_a_stretch()? + .a_fill_rect()? + .close()? + .close()? + .open_pic_sp_pr("auto")? + .open_a_xfrm_with_rot(&format!("{}", (self.rot as u32) * 60 * 1000))? + .a_off("0", "0")? + .a_ext(&format!("{}", self.size.0), &format!("{}", self.size.1))? + .close()? + .open_a_prst_geom("rect")? + .a_av_lst()? + .close()? + .close()? + .close()? + .into_inner() } } @@ -248,30 +250,7 @@ mod tests { let b = Pic::new_with_dimensions(Vec::new(), 320, 240).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - - - - - - - - - - - - - - - - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/positional_tab.rs b/docx-core/src/documents/elements/positional_tab.rs index 91fb181..5ec9ac9 100644 --- a/docx-core/src/documents/elements/positional_tab.rs +++ b/docx-core/src/documents/elements/positional_tab.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -54,9 +55,12 @@ impl PositionalTab { } impl BuildXML for PositionalTab { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.ptab(self.alignment, self.relative_to, self.leader) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .ptab(self.alignment, self.relative_to, self.leader)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/q_format.rs b/docx-core/src/documents/elements/q_format.rs index de55368..0597823 100644 --- a/docx-core/src/documents/elements/q_format.rs +++ b/docx-core/src/documents/elements/q_format.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; //17.7.4.14 // qFormat (Primary Style) @@ -16,11 +17,12 @@ impl QFormat { } } - impl BuildXML for QFormat { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.q_format().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).q_format()?.into_inner() } } diff --git a/docx-core/src/documents/elements/run.rs b/docx-core/src/documents/elements/run.rs index 2291135..7d198b5 100644 --- a/docx-core/src/documents/elements/run.rs +++ b/docx-core/src/documents/elements/run.rs @@ -1,6 +1,7 @@ use super::*; use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -328,33 +329,45 @@ impl Run { } } -impl BuildXML for Run { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_run().add_child(&self.run_property); - for c in &self.children { - match c { - RunChild::Text(t) => b = b.add_child(t), - RunChild::Sym(t) => b = b.add_child(t), - RunChild::DeleteText(t) => b = b.add_child(t), - RunChild::Tab(t) => b = b.add_child(t), - RunChild::PTab(t) => b = b.add_child(t), - RunChild::Break(t) => b = b.add_child(t), - RunChild::Drawing(t) => b = b.add_child(t), - RunChild::Shape(_t) => { - todo!("Support shape writer.") - } - RunChild::CommentStart(c) => b = b.add_child(c), - RunChild::CommentEnd(c) => b = b.add_child(c), - RunChild::FieldChar(c) => b = b.add_child(c), - RunChild::InstrText(c) => b = b.add_child(c), - RunChild::DeleteInstrText(c) => b = b.add_child(c), - RunChild::InstrTextString(_) => unreachable!(), - RunChild::FootnoteReference(c) => b = b.add_child(c), - RunChild::Shading(s) => b = b.add_child(s), +impl BuildXML for RunChild { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + match self { + RunChild::Text(t) => t.build_to(stream), + RunChild::Sym(t) => t.build_to(stream), + RunChild::DeleteText(t) => t.build_to(stream), + RunChild::Tab(t) => t.build_to(stream), + RunChild::PTab(t) => t.build_to(stream), + RunChild::Break(t) => t.build_to(stream), + RunChild::Drawing(t) => t.build_to(stream), + RunChild::Shape(_t) => { + todo!("Support shape writer.") } + RunChild::CommentStart(c) => c.build_to(stream), + RunChild::CommentEnd(c) => c.build_to(stream), + RunChild::FieldChar(c) => c.build_to(stream), + RunChild::InstrText(c) => c.build_to(stream), + RunChild::DeleteInstrText(c) => c.build_to(stream), + RunChild::InstrTextString(_) => unreachable!(), + RunChild::FootnoteReference(c) => c.build_to(stream), + RunChild::Shading(s) => s.build_to(stream), } - b.close().build() + } +} + +impl BuildXML for Run { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_run()? + .add_child(&self.run_property)? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/run_fonts.rs b/docx-core/src/documents/elements/run_fonts.rs index 21a244e..e334ca6 100644 --- a/docx-core/src/documents/elements/run_fonts.rs +++ b/docx-core/src/documents/elements/run_fonts.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -96,20 +97,23 @@ impl RunFonts { } impl BuildXML for RunFonts { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.run_fonts( - self.ascii.as_ref(), - self.hi_ansi.as_ref(), - self.cs.as_ref(), - self.east_asia.as_ref(), - self.ascii_theme.as_ref(), - self.hi_ansi_theme.as_ref(), - self.cs_theme.as_ref(), - self.east_asia_theme.as_ref(), - self.hint.as_ref(), - ) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .run_fonts( + self.ascii.as_ref(), + self.hi_ansi.as_ref(), + self.cs.as_ref(), + self.east_asia.as_ref(), + self.ascii_theme.as_ref(), + self.hi_ansi_theme.as_ref(), + self.cs_theme.as_ref(), + self.east_asia_theme.as_ref(), + self.hint.as_ref(), + )? + .into_inner() } } diff --git a/docx-core/src/documents/elements/run_property.rs b/docx-core/src/documents/elements/run_property.rs index ac6dc15..a8ccc95 100644 --- a/docx-core/src/documents/elements/run_property.rs +++ b/docx-core/src/documents/elements/run_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -171,33 +172,36 @@ impl RunProperty { } impl BuildXML for RunProperty { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_run_property() - .add_optional_child(&self.sz) - .add_optional_child(&self.sz_cs) - .add_optional_child(&self.color) - .add_optional_child(&self.bold) - .add_optional_child(&self.bold_cs) - .add_optional_child(&self.caps) - .add_optional_child(&self.italic) - .add_optional_child(&self.italic_cs) - .add_optional_child(&self.strike) - .add_optional_child(&self.highlight) - .add_optional_child(&self.underline) - .add_optional_child(&self.vanish) - .add_optional_child(&self.spec_vanish) - .add_optional_child(&self.fonts) - .add_optional_child(&self.text_border) - .add_optional_child(&self.ins) - .add_optional_child(&self.del) - .add_optional_child(&self.vert_align) - .add_optional_child(&self.character_spacing) - .add_optional_child(&self.style) - .add_optional_child(&self.positional_tab) - .add_optional_child(&self.shading) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_run_property()? + .add_optional_child(&self.sz)? + .add_optional_child(&self.sz_cs)? + .add_optional_child(&self.color)? + .add_optional_child(&self.bold)? + .add_optional_child(&self.bold_cs)? + .add_optional_child(&self.caps)? + .add_optional_child(&self.italic)? + .add_optional_child(&self.italic_cs)? + .add_optional_child(&self.strike)? + .add_optional_child(&self.highlight)? + .add_optional_child(&self.underline)? + .add_optional_child(&self.vanish)? + .add_optional_child(&self.spec_vanish)? + .add_optional_child(&self.fonts)? + .add_optional_child(&self.text_border)? + .add_optional_child(&self.ins)? + .add_optional_child(&self.del)? + .add_optional_child(&self.vert_align)? + .add_optional_child(&self.character_spacing)? + .add_optional_child(&self.style)? + .add_optional_child(&self.positional_tab)? + .add_optional_child(&self.shading)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/run_property_default.rs b/docx-core/src/documents/elements/run_property_default.rs index 9f5e0f6..eaf9c63 100644 --- a/docx-core/src/documents/elements/run_property_default.rs +++ b/docx-core/src/documents/elements/run_property_default.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -44,12 +45,15 @@ impl Default for RunPropertyDefault { } impl BuildXML for RunPropertyDefault { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.open_run_property_default() - .add_child(&self.run_property) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_run_property_default()? + .add_child(&self.run_property)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/run_style.rs b/docx-core/src/documents/elements/run_style.rs index 6741777..6a50d08 100644 --- a/docx-core/src/documents/elements/run_style.rs +++ b/docx-core/src/documents/elements/run_style.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -26,8 +27,11 @@ impl RunStyle { } impl BuildXML for RunStyle { - fn build(&self) -> Vec { - XMLBuilder::new().run_style(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).run_style(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/section.rs b/docx-core/src/documents/elements/section.rs index 1f0b4cf..e1083a8 100644 --- a/docx-core/src/documents/elements/section.rs +++ b/docx-core/src/documents/elements/section.rs @@ -1,6 +1,7 @@ use super::*; use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -25,16 +26,18 @@ impl Default for Section { } impl BuildXML for Section { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let id = crate::generate_para_id(); - - XMLBuilder::new() - .open_paragraph(&id) - .open_paragraph_property() - .add_child(&self.property) - .close() - .close() - .build() + XMLBuilder::from(stream) + .open_paragraph(&id)? + .open_paragraph_property()? + .add_child(&self.property)? + .close()? + .close()? + .into_inner() } } @@ -52,10 +55,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/section_property.rs b/docx-core/src/documents/elements/section_property.rs index f51b325..e02cc59 100644 --- a/docx-core/src/documents/elements/section_property.rs +++ b/docx-core/src/documents/elements/section_property.rs @@ -3,6 +3,7 @@ use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; use crate::{Footer, Header}; +use std::io::Write; use serde::Serialize; @@ -197,34 +198,30 @@ impl Default for SectionProperty { } impl BuildXML for SectionProperty { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b - .open_section_property() - .add_child(&self.page_size) - .add_child(&self.page_margin) - .columns(&format!("{}", &self.space), &format!("{}", &self.columns)) - .add_optional_child(&self.doc_grid) - .add_optional_child(&self.header_reference) - .add_optional_child(&self.first_header_reference) - .add_optional_child(&self.even_header_reference) - .add_optional_child(&self.footer_reference) - .add_optional_child(&self.first_footer_reference) - .add_optional_child(&self.even_footer_reference) - .add_optional_child(&self.page_num_type); - - if !self.text_direction.eq("lrTb") { - b = b.text_direction(&self.text_direction); - } - if let Some(t) = self.section_type { - b = b.type_tag(&t.to_string()); - } - - if self.title_pg { - b = b.title_pg(); - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_section_property()? + .add_child(&self.page_size)? + .add_child(&self.page_margin)? + .columns(&format!("{}", &self.space), &format!("{}", &self.columns))? + .add_optional_child(&self.doc_grid)? + .add_optional_child(&self.header_reference)? + .add_optional_child(&self.first_header_reference)? + .add_optional_child(&self.even_header_reference)? + .add_optional_child(&self.footer_reference)? + .add_optional_child(&self.first_footer_reference)? + .add_optional_child(&self.even_footer_reference)? + .add_optional_child(&self.page_num_type)? + .apply_if(self.text_direction != "lrTb", |b| { + b.text_direction(&self.text_direction) + })? + .apply_opt(self.section_type, |t, b| b.type_tag(&t.to_string()))? + .apply_if(self.title_pg, |b| b.title_pg())? + .close()? + .into_inner() } } @@ -243,9 +240,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - -"# + r#""# ) } @@ -255,8 +250,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } @@ -276,9 +270,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/shading.rs b/docx-core/src/documents/elements/shading.rs index 2c0d60b..5099a0a 100644 --- a/docx-core/src/documents/elements/shading.rs +++ b/docx-core/src/documents/elements/shading.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -45,9 +46,12 @@ impl Shading { } impl BuildXML for Shading { - fn build(&self) -> Vec { - XMLBuilder::new() - .shd(&self.shd_type.to_string(), &self.color, &self.fill) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .shd(&self.shd_type.to_string(), &self.color, &self.fill)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/spec_vanish.rs b/docx-core/src/documents/elements/spec_vanish.rs index da45187..1774d00 100644 --- a/docx-core/src/documents/elements/spec_vanish.rs +++ b/docx-core/src/documents/elements/spec_vanish.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -13,9 +14,11 @@ impl SpecVanish { } impl BuildXML for SpecVanish { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.spec_vanish().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).spec_vanish()?.into_inner() } } diff --git a/docx-core/src/documents/elements/start.rs b/docx-core/src/documents/elements/start.rs index 434153b..f7feb88 100644 --- a/docx-core/src/documents/elements/start.rs +++ b/docx-core/src/documents/elements/start.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,11 @@ impl Start { } impl BuildXML for Start { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.start(self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).start(self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/strike.rs b/docx-core/src/documents/elements/strike.rs index 8c2e8d3..7814695 100644 --- a/docx-core/src/documents/elements/strike.rs +++ b/docx-core/src/documents/elements/strike.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -35,8 +36,10 @@ impl Serialize for Strike { } impl BuildXML for Strike { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.strike().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).strike()?.into_inner() } } diff --git a/docx-core/src/documents/elements/structured_data_tag.rs b/docx-core/src/documents/elements/structured_data_tag.rs index 11dc089..61ca22f 100644 --- a/docx-core/src/documents/elements/structured_data_tag.rs +++ b/docx-core/src/documents/elements/structured_data_tag.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -37,16 +38,19 @@ pub enum StructuredDataTagChild { } impl BuildXML for StructuredDataTagChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - StructuredDataTagChild::Run(v) => v.build(), - StructuredDataTagChild::Paragraph(v) => v.build(), - StructuredDataTagChild::Table(v) => v.build(), - StructuredDataTagChild::BookmarkStart(v) => v.build(), - StructuredDataTagChild::BookmarkEnd(v) => v.build(), - StructuredDataTagChild::CommentStart(v) => v.build(), - StructuredDataTagChild::CommentEnd(v) => v.build(), - StructuredDataTagChild::StructuredDataTag(v) => v.build(), + StructuredDataTagChild::Run(v) => v.build_to(stream), + StructuredDataTagChild::Paragraph(v) => v.build_to(stream), + StructuredDataTagChild::Table(v) => v.build_to(stream), + StructuredDataTagChild::BookmarkStart(v) => v.build_to(stream), + StructuredDataTagChild::BookmarkEnd(v) => v.build_to(stream), + StructuredDataTagChild::CommentStart(v) => v.build_to(stream), + StructuredDataTagChild::CommentEnd(v) => v.build_to(stream), + StructuredDataTagChild::StructuredDataTag(v) => v.build_to(stream), } } } @@ -147,28 +151,21 @@ impl StructuredDataTag { self.property = self.property.alias(v); self } - - fn inner_build(&self) -> Vec { - XMLBuilder::new() - .open_structured_tag() - .add_child(&self.property) - .open_structured_tag_content() - .add_children(&self.children) - .close() - .close() - .build() - } } impl BuildXML for StructuredDataTag { - fn build(&self) -> Vec { - self.inner_build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - self.inner_build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_structured_tag()? + .add_child(&self.property)? + .open_structured_tag_content()? + .add_children(&self.children)? + .close()? + .close()? + .into_inner() } } @@ -188,8 +185,7 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#"Hello -"# + r#"Hello"# ); } } diff --git a/docx-core/src/documents/elements/structured_data_tag_property.rs b/docx-core/src/documents/elements/structured_data_tag_property.rs index b3f86cb..4709ee8 100644 --- a/docx-core/src/documents/elements/structured_data_tag_property.rs +++ b/docx-core/src/documents/elements/structured_data_tag_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -40,17 +41,17 @@ impl StructuredDataTagProperty { } impl BuildXML for StructuredDataTagProperty { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new() - .open_structured_tag_property() - .add_child(&self.run_property) - .add_optional_child(&self.data_binding); - - if let Some(ref alias) = self.alias { - b = b.alias(alias); - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_structured_tag_property()? + .add_child(&self.run_property)? + .add_optional_child(&self.data_binding)? + .apply_opt(self.alias.as_ref(), |alias, b| b.alias(alias))? + .close()? + .into_inner() } } @@ -78,8 +79,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/style.rs b/docx-core/src/documents/elements/style.rs index d4bd3f1..6b645f4 100644 --- a/docx-core/src/documents/elements/style.rs +++ b/docx-core/src/documents/elements/style.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -316,33 +317,26 @@ impl Style { } impl BuildXML for Style { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { // Set "Normal" as default if you need change these values please fix it - let mut b = b - .open_style(self.style_type, &self.style_id) - .add_child(&self.name) - .add_child(&self.run_property) - .add_child(&self.paragraph_property); - - if self.style_type == StyleType::Table { - b = b - .add_child(&self.table_cell_property) - .add_child(&self.table_property); - } - - if let Some(ref next) = self.next { - b = b.add_child(next) - } - - if let Some(ref link) = self.link { - b = b.add_child(link) - } - - b.add_child(&QFormat::new()) - .add_optional_child(&self.based_on) - .close() - .build() + XMLBuilder::from(stream) + .open_style(self.style_type, &self.style_id)? + .add_child(&self.name)? + .add_child(&self.run_property)? + .add_child(&self.paragraph_property)? + .apply_if(self.style_type == StyleType::Table, |b| { + b.add_child(&self.table_cell_property)? + .add_child(&self.table_property) + })? + .add_optional_child(&self.next)? + .add_optional_child(&self.link)? + .add_child(&QFormat::new())? + .add_optional_child(&self.based_on)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/sym.rs b/docx-core/src/documents/elements/sym.rs index b6de208..d959aa7 100644 --- a/docx-core/src/documents/elements/sym.rs +++ b/docx-core/src/documents/elements/sym.rs @@ -1,5 +1,6 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::Deserialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -20,9 +21,13 @@ impl Sym { } } impl BuildXML for Sym { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.sym(&self.font, &self.char).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .sym(&self.font, &self.char)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/sz.rs b/docx-core/src/documents/elements/sz.rs index d93d1b5..a87173f 100644 --- a/docx-core/src/documents/elements/sz.rs +++ b/docx-core/src/documents/elements/sz.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,11 @@ impl Sz { } impl BuildXML for Sz { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.sz(self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).sz(self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/sz_cs.rs b/docx-core/src/documents/elements/sz_cs.rs index fef38b2..274e6e8 100644 --- a/docx-core/src/documents/elements/sz_cs.rs +++ b/docx-core/src/documents/elements/sz_cs.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::xml_builder::*; use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; #[derive(Deserialize, Debug, Clone, PartialEq)] pub struct SzCs { @@ -14,8 +15,11 @@ impl SzCs { } impl BuildXML for SzCs { - fn build(&self) -> Vec { - XMLBuilder::new().sz_cs(self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).sz_cs(self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/tab.rs b/docx-core/src/documents/elements/tab.rs index 46c6ca2..39ccf01 100644 --- a/docx-core/src/documents/elements/tab.rs +++ b/docx-core/src/documents/elements/tab.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -35,8 +36,12 @@ impl Tab { } impl BuildXML for Tab { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.tab(self.val, self.leader, self.pos).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .tab(self.val, self.leader, self.pos)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table.rs b/docx-core/src/documents/elements/table.rs index b31778a..d3b2f48 100644 --- a/docx-core/src/documents/elements/table.rs +++ b/docx-core/src/documents/elements/table.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -21,9 +22,12 @@ pub enum TableChild { } impl BuildXML for TableChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - TableChild::TableRow(v) => v.build(), + TableChild::TableRow(v) => v.build_to(stream), } } } @@ -122,20 +126,18 @@ impl Table { } impl BuildXML for Table { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let grid = TableGrid::new(self.grid.clone()); - let b = XMLBuilder::new() - .open_table() - .add_child(&self.property) - .add_child(&grid) - .add_children(&self.rows); - b.close().build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - Table::build(self) + XMLBuilder::from(stream) + .open_table()? + .add_child(&self.property)? + .add_child(&grid)? + .add_children(&self.rows)? + .close()? + .into_inner() } } @@ -179,10 +181,7 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - -"# + r#""# ); } diff --git a/docx-core/src/documents/elements/table_borders.rs b/docx-core/src/documents/elements/table_borders.rs index 314a867..3c78fc5 100644 --- a/docx-core/src/documents/elements/table_borders.rs +++ b/docx-core/src/documents/elements/table_borders.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -54,29 +55,22 @@ impl TableBorder { } impl BuildXML for TableBorder { - fn build(&self) -> Vec { - let base = XMLBuilder::new(); - let base = match self.position { - TableBorderPosition::Top => { - base.border_top(self.border_type, self.size, self.space, &self.color) - } - TableBorderPosition::Left => { - base.border_left(self.border_type, self.size, self.space, &self.color) - } - TableBorderPosition::Bottom => { - base.border_bottom(self.border_type, self.size, self.space, &self.color) - } - TableBorderPosition::Right => { - base.border_right(self.border_type, self.size, self.space, &self.color) - } - TableBorderPosition::InsideH => { - base.border_inside_h(self.border_type, self.size, self.space, &self.color) - } - TableBorderPosition::InsideV => { - base.border_inside_v(self.border_type, self.size, self.space, &self.color) - } + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let func = match self.position { + TableBorderPosition::Top => XMLBuilder::border_top, + TableBorderPosition::Left => XMLBuilder::border_left, + TableBorderPosition::Bottom => XMLBuilder::border_bottom, + TableBorderPosition::Right => XMLBuilder::border_right, + TableBorderPosition::InsideH => XMLBuilder::border_inside_h, + TableBorderPosition::InsideV => XMLBuilder::border_inside_v, }; - base.build() + + XMLBuilder::from(stream) + .apply(|b| func(b, self.border_type, self.size, self.space, &self.color))? + .into_inner() } } @@ -161,17 +155,20 @@ impl TableBorders { } impl BuildXML for TableBorders { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_table_borders() - .add_optional_child(&self.top) - .add_optional_child(&self.left) - .add_optional_child(&self.bottom) - .add_optional_child(&self.right) - .add_optional_child(&self.inside_h) - .add_optional_child(&self.inside_v) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_borders()? + .add_optional_child(&self.top)? + .add_optional_child(&self.left)? + .add_optional_child(&self.bottom)? + .add_optional_child(&self.right)? + .add_optional_child(&self.inside_h)? + .add_optional_child(&self.inside_v)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_cell.rs b/docx-core/src/documents/elements/table_cell.rs index c757112..daaf79d 100644 --- a/docx-core/src/documents/elements/table_cell.rs +++ b/docx-core/src/documents/elements/table_cell.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -153,28 +154,29 @@ impl Default for TableCell { } impl BuildXML for TableCell { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_table_cell().add_child(&self.property); - for c in &self.children { - match c { - TableCellContent::Paragraph(p) => b = b.add_child(p), - TableCellContent::Table(t) => { - b = b.add_child(t); - // INFO: We need to add empty paragraph when parent cell includes only cell. - if self.children.len() == 1 { - b = b.add_child(&Paragraph::new()) + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_cell()? + .add_child(&self.property)? + .apply_each(&self.children, |ch, b| { + match ch { + TableCellContent::Paragraph(p) => b.add_child(p), + TableCellContent::Table(t) => { + b.add_child(t)? + // INFO: We need to add empty paragraph when parent cell includes only cell. + .apply_if(self.children.len() == 1, |b| b.add_child(&Paragraph::new())) } + TableCellContent::StructuredDataTag(t) => b.add_child(&t), + TableCellContent::TableOfContents(t) => b.add_child(&t), } - TableCellContent::StructuredDataTag(t) => b = b.add_child(t), - TableCellContent::TableOfContents(t) => b = b.add_child(t), - } - } - // INFO: We need to add empty paragraph when parent cell includes only cell. - if self.children.is_empty() { - b = b.add_child(&Paragraph::new()) - } - b.close().build() + })? + // INFO: We need to add empty paragraph when parent cell includes only cell. + .apply_if(self.children.is_empty(), |b| b.add_child(&Paragraph::new()))? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_cell_borders.rs b/docx-core/src/documents/elements/table_cell_borders.rs index e8aa9ec..3a55f07 100644 --- a/docx-core/src/documents/elements/table_cell_borders.rs +++ b/docx-core/src/documents/elements/table_cell_borders.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -68,35 +69,23 @@ impl TableCellBorder { } impl BuildXML for TableCellBorder { - fn build(&self) -> Vec { - let base = XMLBuilder::new(); - let base = match self.position { - TableCellBorderPosition::Top => { - base.border_top(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::Left => { - base.border_left(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::Bottom => { - base.border_bottom(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::Right => { - base.border_right(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::InsideH => { - base.border_inside_h(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::InsideV => { - base.border_inside_v(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::Tr2bl => { - base.border_tr2bl(self.border_type, self.size, self.space, &self.color) - } - TableCellBorderPosition::Tl2br => { - base.border_tl2br(self.border_type, self.size, self.space, &self.color) - } + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let func = match self.position { + TableCellBorderPosition::Top => XMLBuilder::border_top, + TableCellBorderPosition::Left => XMLBuilder::border_left, + TableCellBorderPosition::Bottom => XMLBuilder::border_bottom, + TableCellBorderPosition::Right => XMLBuilder::border_right, + TableCellBorderPosition::InsideH => XMLBuilder::border_inside_h, + TableCellBorderPosition::InsideV => XMLBuilder::border_inside_v, + TableCellBorderPosition::Tr2bl => XMLBuilder::border_tr2bl, + TableCellBorderPosition::Tl2br => XMLBuilder::border_tl2br, }; - base.build() + XMLBuilder::from(stream) + .apply(|b| func(b, self.border_type, self.size, self.space, &self.color))? + .into_inner() } } @@ -202,18 +191,21 @@ impl TableCellBorders { } impl BuildXML for TableCellBorders { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_table_cell_borders() - .add_optional_child(&self.top) - .add_optional_child(&self.left) - .add_optional_child(&self.bottom) - .add_optional_child(&self.right) - .add_optional_child(&self.inside_h) - .add_optional_child(&self.inside_v) - .add_optional_child(&self.tl2br) - .add_optional_child(&self.tr2bl) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_cell_borders()? + .add_optional_child(&self.top)? + .add_optional_child(&self.left)? + .add_optional_child(&self.bottom)? + .add_optional_child(&self.right)? + .add_optional_child(&self.inside_h)? + .add_optional_child(&self.inside_v)? + .add_optional_child(&self.tl2br)? + .add_optional_child(&self.tr2bl)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_cell_margins.rs b/docx-core/src/documents/elements/table_cell_margins.rs index 14a08a8..0403b24 100644 --- a/docx-core/src/documents/elements/table_cell_margins.rs +++ b/docx-core/src/documents/elements/table_cell_margins.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -67,15 +68,18 @@ impl TableCellMargins { } impl BuildXML for TableCellMargins { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_table_cell_margins() - .margin_top(self.top.val as i32, self.top.width_type) - .margin_left(self.left.val as i32, self.left.width_type) - .margin_bottom(self.bottom.val as i32, self.bottom.width_type) - .margin_right(self.right.val as i32, self.right.width_type) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_cell_margins()? + .margin_top(self.top.val as i32, self.top.width_type)? + .margin_left(self.left.val as i32, self.left.width_type)? + .margin_bottom(self.bottom.val as i32, self.bottom.width_type)? + .margin_right(self.right.val as i32, self.right.width_type)? + .close()? + .into_inner() } } @@ -92,12 +96,7 @@ mod tests { let b = TableCellMargins::new().build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - -"# + r#""# ); } @@ -106,12 +105,7 @@ mod tests { let b = TableCellMargins::new().margin(10, 20, 30, 40).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/table_cell_property.rs b/docx-core/src/documents/elements/table_cell_property.rs index 9a7f476..bde82f7 100644 --- a/docx-core/src/documents/elements/table_cell_property.rs +++ b/docx-core/src/documents/elements/table_cell_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -124,19 +125,22 @@ impl TableCellProperty { } impl BuildXML for TableCellProperty { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_table_cell_property() - .add_optional_child(&self.width) - .add_optional_child(&self.borders) - .add_optional_child(&self.grid_span) - .add_optional_child(&self.vertical_merge) - .add_optional_child(&self.vertical_align) - .add_optional_child(&self.text_direction) - .add_optional_child(&self.shading) - .add_optional_child(&self.margins) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_cell_property()? + .add_optional_child(&self.width)? + .add_optional_child(&self.borders)? + .add_optional_child(&self.grid_span)? + .add_optional_child(&self.vertical_merge)? + .add_optional_child(&self.vertical_align)? + .add_optional_child(&self.text_direction)? + .add_optional_child(&self.shading)? + .add_optional_child(&self.margins)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_cell_width.rs b/docx-core/src/documents/elements/table_cell_width.rs index 195c85b..cacd0fa 100644 --- a/docx-core/src/documents/elements/table_cell_width.rs +++ b/docx-core/src/documents/elements/table_cell_width.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -18,10 +19,13 @@ impl TableCellWidth { } impl BuildXML for TableCellWidth { - fn build(&self) -> Vec { - XMLBuilder::new() - .table_cell_width(self.width as i32, WidthType::Dxa) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .table_cell_width(self.width as i32, WidthType::Dxa)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_grid.rs b/docx-core/src/documents/elements/table_grid.rs index 5b654af..a535e2b 100644 --- a/docx-core/src/documents/elements/table_grid.rs +++ b/docx-core/src/documents/elements/table_grid.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; +use std::io::Write; #[derive(Debug, Clone)] pub struct TableGrid { @@ -14,12 +15,15 @@ impl TableGrid { } impl BuildXML for TableGrid { - fn build(&self) -> Vec { - let mut base = XMLBuilder::new().open_table_grid(); - for g in &self.grid { - base = base.grid_column(*g as i32, WidthType::Dxa); - } - base.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_grid()? + .apply_each(&self.grid, |g, b| b.grid_column(*g as i32, WidthType::Dxa))? + .close()? + .into_inner() } } @@ -36,10 +40,7 @@ mod tests { let b = TableGrid::new(vec![100, 200]).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/elements/table_indent.rs b/docx-core/src/documents/elements/table_indent.rs index b94e21c..74fa04c 100644 --- a/docx-core/src/documents/elements/table_indent.rs +++ b/docx-core/src/documents/elements/table_indent.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -18,10 +19,13 @@ impl TableIndent { } impl BuildXML for TableIndent { - fn build(&self) -> Vec { - XMLBuilder::new() - .table_indent(self.width, WidthType::Dxa) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .table_indent(self.width, WidthType::Dxa)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_layout.rs b/docx-core/src/documents/elements/table_layout.rs index 1894bc0..fd2a5cc 100644 --- a/docx-core/src/documents/elements/table_layout.rs +++ b/docx-core/src/documents/elements/table_layout.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -11,16 +12,18 @@ pub struct TableLayout { impl TableLayout { pub fn new(t: TableLayoutType) -> TableLayout { - TableLayout { - layout_type: t, - } + TableLayout { layout_type: t } } } impl BuildXML for TableLayout { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.table_layout(&self.layout_type.to_string()).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .table_layout(&self.layout_type.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_of_contents.rs b/docx-core/src/documents/elements/table_of_contents.rs index fcbb184..2e5e341 100644 --- a/docx-core/src/documents/elements/table_of_contents.rs +++ b/docx-core/src/documents/elements/table_of_contents.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::types::*; use crate::xml_builder::*; @@ -148,29 +149,35 @@ impl TableOfContents { self.without_sdt = true; self } +} - fn inner_build(&self) -> Vec { +impl BuildXML for TableOfContents { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let mut p = StructuredDataTagProperty::new(); if let Some(ref alias) = self.alias { p = p.alias(alias); } + if self.items.is_empty() { - let mut b = XMLBuilder::new(); + let mut b = XMLBuilder::from(stream); if !self.without_sdt { b = b - .open_structured_tag() - .add_child(&p) - .open_structured_tag_content(); + .open_structured_tag()? + .add_child(&p)? + .open_structured_tag_content()?; } for c in self.before_contents.iter() { match c { TocContent::Paragraph(p) => { - b = b.add_child(p); + b = b.add_child(&p)?; } TocContent::Table(t) => { - b = b.add_child(t); + b = b.add_child(&t)?; } } } @@ -192,11 +199,11 @@ impl TableOfContents { .add_field_char(FieldCharType::Separate, false), ) }; - b = b.add_child(&p1); + b = b.add_child(&p1)?; let p2 = Paragraph::new().add_run(Run::new().add_field_char(FieldCharType::End, false)); if self.after_contents.is_empty() { - b = b.add_child(&p2); + b = b.add_child(&p2)?; } else { for (i, c) in self.after_contents.iter().enumerate() { match c { @@ -210,28 +217,30 @@ impl TableOfContents { Run::new().add_field_char(FieldCharType::End, false), )), ); - b = b.add_child(&new_p) + b = b.add_child(&new_p)? } else { - b = b.add_child(p); + b = b.add_child(&p)?; } } TocContent::Table(t) => { // insert empty line for table // because it causes docx error if table is added after TOC if i == 0 { - b = b.add_child(&Paragraph::new().add_run(Run::new().add_text(""))); + b = b.add_child( + &Paragraph::new().add_run(Run::new().add_text("")), + )?; } - b = b.add_child(t); + b = b.add_child(&t)?; } } } } if !self.without_sdt { - b = b.close().close(); + b = b.close()?.close()?; } - b.build() + b.into_inner() } else { let items: Vec = self .items @@ -247,64 +256,52 @@ impl TableOfContents { }) .collect(); - let mut b = XMLBuilder::new(); + let mut b = XMLBuilder::from(stream); if !self.without_sdt { b = b - .open_structured_tag() - .add_child(&p) - .open_structured_tag_content(); + .open_structured_tag()? + .add_child(&p)? + .open_structured_tag_content()?; } for c in self.before_contents.iter() { match c { TocContent::Paragraph(p) => { - b = b.add_child(p); + b = b.add_child(&p)?; } TocContent::Table(t) => { - b = b.add_child(t); + b = b.add_child(&t)?; } } } - b = b.add_child(&items); + b = b.add_child(&items)?; for (i, c) in self.after_contents.iter().enumerate() { match c { TocContent::Paragraph(p) => { - b = b.add_child(p); + b = b.add_child(&p)?; } TocContent::Table(t) => { // insert empty line for table // because it causes docx error if table is added after TOC if i == 0 { - b = b.add_child(&Paragraph::new().add_run(Run::new().add_text(""))); + b = b.add_child(&Paragraph::new().add_run(Run::new().add_text("")))?; } - b = b.add_child(t); + b = b.add_child(&t)?; } } } if !self.without_sdt { - b = b.close().close(); + b = b.close()?.close()?; } - b.build() + b.into_inner() } } } -impl BuildXML for TableOfContents { - fn build(&self) -> Vec { - self.inner_build() - } -} - -impl BuildXML for Box { - fn build(&self) -> Vec { - self.inner_build() - } -} - #[cfg(test)] mod tests { @@ -318,8 +315,7 @@ mod tests { let b = TableOfContents::new().heading_styles_range(1, 3).build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#"TOC \o "1-3" -"# + r#"TOC \o "1-3""# ); } @@ -336,19 +332,16 @@ mod tests { } /* - #[test] - fn test_toc_with_items() { - let b = TableOfContents::new() - .heading_styles_range(1, 3) - .add_items(Paragraph::new().add_run(Run::new().add_text("Hello"))) - .build(); - assert_eq!( - str::from_utf8(&b).unwrap(), - r#" - - TOC \o "1-3"Hello - "# - ); - } - */ + #[test] + fn test_toc_with_items() { + let b = TableOfContents::new() + .heading_styles_range(1, 3) + .add_items(Paragraph::new().add_run(Run::new().add_text("Hello"))) + .build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#"TOC \o "1-3"Hello"# + ); + } + */ } diff --git a/docx-core/src/documents/elements/table_of_contents_item.rs b/docx-core/src/documents/elements/table_of_contents_item.rs index 85f126e..48d5f7f 100644 --- a/docx-core/src/documents/elements/table_of_contents_item.rs +++ b/docx-core/src/documents/elements/table_of_contents_item.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::*; use crate::types::*; @@ -49,15 +50,19 @@ impl TableOfContentsItem { } impl BuildXML for Vec { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new() - .open_structured_tag() - .open_structured_tag_property() - .close() - .open_structured_tag_content(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let mut b = XMLBuilder::from(stream) + .open_structured_tag()? + .open_structured_tag_property()? + .close()? + .open_structured_tag_content()?; for (i, t) in self.iter().enumerate() { let mut p = Paragraph::new().style(&format!("ToC{}", t.level)); + if i == 0 { p = p.unshift_run( Run::new() @@ -65,40 +70,9 @@ impl BuildXML for Vec { .add_instr_text(InstrText::TOC(t.instr.clone())) .add_field_char(FieldCharType::Separate, false), ); - p = p.add_tab( - Tab::new() - .val(TabValueType::Right) - .leader(TabLeaderType::Dot) - // TODO: for now set 80000 - .pos(80000), - ); + } - let run = Run::new().add_text(&t.text); - let page_ref = Run::new() - .add_field_char(FieldCharType::Begin, false) - .add_instr_text(InstrText::PAGEREF( - InstrPAGEREF::new(&t.toc_key).hyperlink(), - )) - .add_field_char(FieldCharType::Separate, false) - .add_text(t.page_ref.to_owned().unwrap_or_else(|| "1".to_string())) - .add_field_char(FieldCharType::End, false); - - if t.instr.hyperlink { - p = p.add_hyperlink( - Hyperlink::new(&t.toc_key, crate::types::HyperlinkType::Anchor) - .add_run(run) - .add_run(Run::new().add_tab()) - .add_run(page_ref), - ); - } else { - p = p - .add_run(run) - .add_run(Run::new().add_tab()) - .add_run(page_ref); - } - b = b.add_child(&p); - } else { - let mut p = Paragraph::new().style(&format!("ToC{}", t.level)); + { p = p.add_tab( Tab::new() .val(TabValueType::Right) @@ -123,22 +97,23 @@ impl BuildXML for Vec { .add_run(run) .add_run(Run::new().add_tab()) .add_run(page_ref), - ) + ); } else { p = p .add_run(run) .add_run(Run::new().add_tab()) .add_run(page_ref); } - b = b.add_child(&p); + b = b.add_child(&p)?; } if i == self.len() - 1 { let mut p = Paragraph::new().style(&format!("ToC{}", t.level)); p = p.add_run(Run::new().add_field_char(FieldCharType::End, false)); - b = b.add_child(&p); + b = b.add_child(&p)?; } } - b.close().close().build() + + b.close()?.close()?.into_inner() } } diff --git a/docx-core/src/documents/elements/table_position_property.rs b/docx-core/src/documents/elements/table_position_property.rs index 357db82..ea233e7 100644 --- a/docx-core/src/documents/elements/table_position_property.rs +++ b/docx-core/src/documents/elements/table_position_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -73,8 +74,13 @@ impl TablePositionProperty { } impl BuildXML for TablePositionProperty { - fn build(&self) -> Vec { - XMLBuilder::new().table_position_property(self).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .table_position_property(self)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_property.rs b/docx-core/src/documents/elements/table_property.rs index 24edd87..35141f7 100644 --- a/docx-core/src/documents/elements/table_property.rs +++ b/docx-core/src/documents/elements/table_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -150,19 +151,22 @@ impl TableProperty { } impl BuildXML for TableProperty { - fn build(&self) -> Vec { - XMLBuilder::new() - .open_table_property() - .add_child(&self.width) - .add_child(&self.justification) - .add_child(&self.borders) - .add_optional_child(&self.margins) - .add_optional_child(&self.indent) - .add_optional_child(&self.style) - .add_optional_child(&self.layout) - .add_optional_child(&self.position) - .close() - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_property()? + .add_child(&self.width)? + .add_child(&self.justification)? + .add_child(&self.borders)? + .add_optional_child(&self.margins)? + .add_optional_child(&self.indent)? + .add_optional_child(&self.style)? + .add_optional_child(&self.layout)? + .add_optional_child(&self.position)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_row.rs b/docx-core/src/documents/elements/table_row.rs index 12c34db..61cecae 100644 --- a/docx-core/src/documents/elements/table_row.rs +++ b/docx-core/src/documents/elements/table_row.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::{Delete, Insert, TableCell, TableRowProperty}; use crate::xml_builder::*; @@ -19,9 +20,12 @@ pub enum TableRowChild { } impl BuildXML for TableRowChild { - fn build(&self) -> Vec { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { match self { - TableRowChild::TableCell(v) => v.build(), + TableRowChild::TableCell(v) => v.build_to(stream), } } } @@ -85,12 +89,16 @@ impl TableRow { } impl BuildXML for TableRow { - fn build(&self) -> Vec { - let b = XMLBuilder::new() - .open_table_row() - .add_child(&self.property) - .add_children(&self.cells); - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_row()? + .add_child(&self.property)? + .add_children(&self.cells)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_row_property.rs b/docx-core/src/documents/elements/table_row_property.rs index f4e6dcc..1931ac7 100644 --- a/docx-core/src/documents/elements/table_row_property.rs +++ b/docx-core/src/documents/elements/table_row_property.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::xml_builder::*; @@ -75,19 +76,23 @@ impl TableRowProperty { } impl BuildXML for TableRowProperty { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new() - .open_table_row_property() - .add_optional_child(&self.del) - .add_optional_child(&self.ins) - .add_optional_child(&self.cant_split); - if let Some(h) = self.row_height { - b = b.table_row_height( - &format!("{}", h), - &self.height_rule.unwrap_or_default().to_string(), - ) - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_table_row_property()? + .add_optional_child(&self.del)? + .add_optional_child(&self.ins)? + .add_optional_child(&self.cant_split)? + .apply_opt(self.row_height, |h, b| { + b.table_row_height( + &format!("{}", h), + &self.height_rule.unwrap_or_default().to_string(), + ) + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_style.rs b/docx-core/src/documents/elements/table_style.rs index 3c62077..605d6e2 100644 --- a/docx-core/src/documents/elements/table_style.rs +++ b/docx-core/src/documents/elements/table_style.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,9 +16,13 @@ impl TableStyle { } impl BuildXML for TableStyle { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.table_style(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .table_style(&self.val)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/table_width.rs b/docx-core/src/documents/elements/table_width.rs index 5ea09e1..f56b3e2 100644 --- a/docx-core/src/documents/elements/table_width.rs +++ b/docx-core/src/documents/elements/table_width.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -18,10 +19,13 @@ impl TableWidth { } impl BuildXML for TableWidth { - fn build(&self) -> Vec { - XMLBuilder::new() - .table_width(self.width as i32, self.width_type) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .table_width(self.width as i32, self.width_type)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/tabs.rs b/docx-core/src/documents/elements/tabs.rs index fe76e32..7147807 100644 --- a/docx-core/src/documents/elements/tabs.rs +++ b/docx-core/src/documents/elements/tabs.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -21,11 +22,12 @@ impl Tabs { } impl BuildXML for Tabs { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - for t in self.tabs.iter() { - b = b.tab(t.val, t.leader, t.pos); - } - b.build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .apply_each(&self.tabs, |t, b| b.tab(t.val, t.leader, t.pos))? + .into_inner() } } diff --git a/docx-core/src/documents/elements/text.rs b/docx-core/src/documents/elements/text.rs index aab291c..6bd902d 100644 --- a/docx-core/src/documents/elements/text.rs +++ b/docx-core/src/documents/elements/text.rs @@ -1,5 +1,6 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::Deserialize; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -29,8 +30,13 @@ impl Text { } impl BuildXML for Text { - fn build(&self) -> Vec { - XMLBuilder::new().text(&self.text, true).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .text(&self.text, true)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/text_alignment.rs b/docx-core/src/documents/elements/text_alignment.rs index afe9f3e..53f4195 100644 --- a/docx-core/src/documents/elements/text_alignment.rs +++ b/docx-core/src/documents/elements/text_alignment.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::{xml_builder::*, TextAlignmentType}; @@ -13,10 +14,13 @@ impl TextAlignment { } impl BuildXML for TextAlignment { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let v = format!("{}", self.0); - b.text_alignment(&v).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .text_alignment(&format!("{}", self.0))? + .into_inner() } } diff --git a/docx-core/src/documents/elements/text_border.rs b/docx-core/src/documents/elements/text_border.rs index eb14d8c..3748081 100644 --- a/docx-core/src/documents/elements/text_border.rs +++ b/docx-core/src/documents/elements/text_border.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -51,9 +52,12 @@ impl Default for TextBorder { } impl BuildXML for TextBorder { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.text_border(self.border_type, self.size, self.space, &self.color) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .text_border(self.border_type, self.size, self.space, &self.color)? + .into_inner() } } diff --git a/docx-core/src/documents/elements/text_box.rs b/docx-core/src/documents/elements/text_box.rs index f6ea0bc..846900e 100644 --- a/docx-core/src/documents/elements/text_box.rs +++ b/docx-core/src/documents/elements/text_box.rs @@ -143,36 +143,36 @@ impl TextBox { } /* -impl BuildXML for Textbox { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); +impl BuildXML for TextBox { + fn build_to(&self, stream: xml::writer::EventWriter) -> xml::writer::Result> { let w = format!("{}", self.size.0); let h = format!("{}", self.size.1); - b.open_pic("http://schemas.openxmlformats.org/drawingml/2006/picture") - .open_pic_nv_pic_pr() - .pic_c_nv_pr("0", "") - .open_pic_c_nv_pic_pr() - .a_pic_locks("1", "1") - .close() - .close() - .open_blip_fill() - .a_blip(&self.id) - .a_src_rect() - .open_a_stretch() - .a_fill_rect() - .close() - .close() - .open_pic_sp_pr("auto") - .open_a_xfrm() - .a_off("0", "0") - .a_ext(&w, &h) - .close() - .open_a_prst_geom("rect") - .a_av_lst() - .close() - .close() - .close() - .build() + XMLBuilder::from(stream) + .open_pic("http://schemas.openxmlformats.org/drawingml/2006/picture")? + .open_pic_nv_pic_pr()? + .pic_c_nv_pr("0", "")? + .open_pic_c_nv_pic_pr()? + .a_pic_locks("1", "1")? + .close()? + .close()? + .open_blip_fill()? + .a_blip(&self.id)? + .a_src_rect()? + .open_a_stretch()? + .a_fill_rect()? + .close()? + .close()? + .open_pic_sp_pr("auto")? + .open_a_xfrm()? + .a_off("0", "0")? + .a_ext(&w, &h)? + .close()? + .open_a_prst_geom("rect")? + .a_av_lst()? + .close()? + .close()? + .close()? + .into_inner() } } */ diff --git a/docx-core/src/documents/elements/text_box_content.rs b/docx-core/src/documents/elements/text_box_content.rs index 5689507..ced501e 100644 --- a/docx-core/src/documents/elements/text_box_content.rs +++ b/docx-core/src/documents/elements/text_box_content.rs @@ -1,6 +1,7 @@ use super::*; use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -62,17 +63,28 @@ impl TextBoxContent { } } -impl BuildXML for TextBoxContent { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_text_box_content(); - for c in &self.children { - match c { - TextBoxContentChild::Paragraph(p) => b = b.add_child(p), - TextBoxContentChild::Table(t) => b = b.add_child(t), - } +impl BuildXML for TextBoxContentChild { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + match self { + TextBoxContentChild::Paragraph(p) => p.build_to(stream), + TextBoxContentChild::Table(t) => t.build_to(stream), } - b.close().build() + } +} + +impl BuildXML for TextBoxContent { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_text_box_content()? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/text_direction.rs b/docx-core/src/documents/elements/text_direction.rs index 7445aaf..f939b4e 100644 --- a/docx-core/src/documents/elements/text_direction.rs +++ b/docx-core/src/documents/elements/text_direction.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -16,10 +17,13 @@ impl TextDirection { } impl BuildXML for TextDirection { - fn build(&self) -> Vec { - XMLBuilder::new() - .text_direction(&self.val.to_string()) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .text_direction(&self.val.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/underline.rs b/docx-core/src/documents/elements/underline.rs index 1a8a88f..b64e55e 100644 --- a/docx-core/src/documents/elements/underline.rs +++ b/docx-core/src/documents/elements/underline.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -15,8 +16,11 @@ impl Underline { } impl BuildXML for Underline { - fn build(&self) -> Vec { - XMLBuilder::new().underline(&self.val).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).underline(&self.val)?.into_inner() } } diff --git a/docx-core/src/documents/elements/v_align.rs b/docx-core/src/documents/elements/v_align.rs index ea2db75..7f214ce 100644 --- a/docx-core/src/documents/elements/v_align.rs +++ b/docx-core/src/documents/elements/v_align.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -16,10 +17,13 @@ impl VAlign { } impl BuildXML for VAlign { - fn build(&self) -> Vec { - XMLBuilder::new() - .vertical_align(&self.val.to_string()) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .vertical_align(&self.val.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/vanish.rs b/docx-core/src/documents/elements/vanish.rs index eee3eac..60e4ac5 100644 --- a/docx-core/src/documents/elements/vanish.rs +++ b/docx-core/src/documents/elements/vanish.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -13,9 +14,11 @@ impl Vanish { } impl BuildXML for Vanish { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.vanish().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream).vanish()?.into_inner() } } diff --git a/docx-core/src/documents/elements/vert_align.rs b/docx-core/src/documents/elements/vert_align.rs index becc997..1eab4ad 100644 --- a/docx-core/src/documents/elements/vert_align.rs +++ b/docx-core/src/documents/elements/vert_align.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -25,8 +26,12 @@ impl Serialize for VertAlign { } impl BuildXML for VertAlign { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.vert_align(&self.val.to_string() ).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .vert_align(&self.val.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/vertical_merge.rs b/docx-core/src/documents/elements/vertical_merge.rs index f7e08b8..9bf7d9e 100644 --- a/docx-core/src/documents/elements/vertical_merge.rs +++ b/docx-core/src/documents/elements/vertical_merge.rs @@ -1,4 +1,5 @@ use serde::{Serialize, Serializer}; +use std::io::Write; use crate::documents::BuildXML; use crate::types::*; @@ -16,10 +17,13 @@ impl VMerge { } impl BuildXML for VMerge { - fn build(&self) -> Vec { - XMLBuilder::new() - .vertical_merge(&self.val.to_string()) - .build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .vertical_merge(&self.val.to_string())? + .into_inner() } } diff --git a/docx-core/src/documents/elements/wp_anchor.rs b/docx-core/src/documents/elements/wp_anchor.rs index 650152a..51068f8 100644 --- a/docx-core/src/documents/elements/wp_anchor.rs +++ b/docx-core/src/documents/elements/wp_anchor.rs @@ -1,5 +1,6 @@ use super::*; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -33,13 +34,15 @@ impl WpAnchor { } impl BuildXML for WpAnchor { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_anchor(); - for c in &self.children { - b = b.add_child(c) - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_anchor()? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/wps_shape.rs b/docx-core/src/documents/elements/wps_shape.rs index ab2a0ea..9c89c86 100644 --- a/docx-core/src/documents/elements/wps_shape.rs +++ b/docx-core/src/documents/elements/wps_shape.rs @@ -1,6 +1,7 @@ use super::*; use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -43,15 +44,26 @@ impl WpsShape { } } -impl BuildXML for WpsShape { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_wp_text_box(); - for c in &self.children { - match c { - WpsShapeChild::WpsTextBox(t) => b = b.add_child(t), - } +impl BuildXML for WpsShapeChild { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + match self { + WpsShapeChild::WpsTextBox(t) => t.build_to(stream), } - b.close().build() + } +} + +impl BuildXML for WpsShape { + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_wp_text_box()? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/wps_text_box.rs b/docx-core/src/documents/elements/wps_text_box.rs index 0a5178b..aeb22ef 100644 --- a/docx-core/src/documents/elements/wps_text_box.rs +++ b/docx-core/src/documents/elements/wps_text_box.rs @@ -1,5 +1,6 @@ use super::*; use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -26,13 +27,15 @@ impl WpsTextBox { } impl BuildXML for WpsTextBox { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b.open_wp_text_box(); - for c in &self.children { - b = b.add_child(c); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .open_wp_text_box()? + .add_children(&self.children)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/elements/zoom.rs b/docx-core/src/documents/elements/zoom.rs index a032b87..9fe81df 100644 --- a/docx-core/src/documents/elements/zoom.rs +++ b/docx-core/src/documents/elements/zoom.rs @@ -1,5 +1,6 @@ use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::{Serialize, Serializer}; @@ -15,9 +16,13 @@ impl Zoom { } impl BuildXML for Zoom { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - b.zoom(&format!("{}", self.val)).build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .zoom(&format!("{}", self.val))? + .into_inner() } } diff --git a/docx-core/src/documents/font_table.rs b/docx-core/src/documents/font_table.rs index dd06237..c30be05 100644 --- a/docx-core/src/documents/font_table.rs +++ b/docx-core/src/documents/font_table.rs @@ -2,6 +2,7 @@ use super::Font; use crate::documents::BuildXML; use crate::types::FontPitchType; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -16,18 +17,21 @@ impl FontTable { } impl BuildXML for FontTable { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + let b = XMLBuilder::from(stream); let times = Font::new("Times New Roman", "00", "roman", FontPitchType::Variable); let symbol = Font::new("Symbol", "02", "roman", FontPitchType::Variable); let arial = Font::new("Arial", "00", "swiss", FontPitchType::Variable); - b.declaration(Some(true)) - .open_fonts() - .add_child(×) - .add_child(&symbol) - .add_child(&arial) - .close() - .build() + b.declaration(Some(true))? + .open_fonts()? + .add_child(×)? + .add_child(&symbol)? + .add_child(&arial)? + .close()? + .into_inner() } } @@ -35,30 +39,16 @@ impl BuildXML for FontTable { mod tests { use super::*; - #[cfg(test)] - use pretty_assertions::assert_eq; + use pretty_assertions::assert_str_eq; use std::str; #[test] fn test_settings() { let c = FontTable::new(); let b = c.build(); - assert_eq!( + assert_str_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - - - - - - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/footer.rs b/docx-core/src/documents/footer.rs index 6c87565..6dba96c 100644 --- a/docx-core/src/documents/footer.rs +++ b/docx-core/src/documents/footer.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -80,18 +81,20 @@ impl Serialize for FooterChild { } impl BuildXML for Footer { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b.declaration(Some(true)).open_footer(); - - for c in &self.children { - match c { - FooterChild::Paragraph(p) => b = b.add_child(p), - FooterChild::Table(t) => b = b.add_child(t), - FooterChild::StructuredDataTag(t) => b = b.add_child(t), - } - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_footer()? + .apply_each(&self.children, |c, b| match c { + FooterChild::Paragraph(p) => b.add_child(&p), + FooterChild::Table(t) => b.add_child(&t), + FooterChild::StructuredDataTag(t) => b.add_child(&t), + })? + .close()? + .into_inner() } } @@ -109,8 +112,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } } diff --git a/docx-core/src/documents/footer_rels.rs b/docx-core/src/documents/footer_rels.rs index 9518fac..4ffb040 100644 --- a/docx-core/src/documents/footer_rels.rs +++ b/docx-core/src/documents/footer_rels.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::{xml_builder::*, ImageIdAndPath}; use serde::Serialize; +use std::io::Write; #[derive(Debug, Clone, PartialEq, Serialize, Default)] #[serde(rename_all = "camelCase")] @@ -24,20 +25,21 @@ impl FooterRels { } impl BuildXML for FooterRels { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b - .declaration(None) - .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships"); - - for (id, path) in self.images.iter() { - b = b.relationship( - id, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - path, - ) - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(None)? + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")? + .apply_each(&self.images, |(id, path), b| { + b.relationship( + id, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + path, + ) + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/footnotes.rs b/docx-core/src/documents/footnotes.rs index e0dd113..91f7232 100644 --- a/docx-core/src/documents/footnotes.rs +++ b/docx-core/src/documents/footnotes.rs @@ -1,6 +1,7 @@ use super::Footnote; use crate::documents::BuildXML; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -21,12 +22,16 @@ impl Footnotes { } impl BuildXML for Footnotes { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new().declaration(Some(true)).open_footnotes(); - for c in &self.footnotes { - b = b.add_child(c) - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_footnotes()? + .add_children(&self.footnotes)? + .close()? + .into_inner() } } @@ -43,8 +48,7 @@ mod tests { let b = Footnotes::new().build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } } diff --git a/docx-core/src/documents/header.rs b/docx-core/src/documents/header.rs index 8df882b..d19e0b7 100644 --- a/docx-core/src/documents/header.rs +++ b/docx-core/src/documents/header.rs @@ -1,5 +1,6 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -80,18 +81,20 @@ impl Serialize for HeaderChild { } impl BuildXML for Header { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b.declaration(Some(true)).open_header(); - - for c in &self.children { - match c { - HeaderChild::Paragraph(p) => b = b.add_child(p), - HeaderChild::Table(t) => b = b.add_child(t), - HeaderChild::StructuredDataTag(t) => b = b.add_child(t), - } - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_header()? + .apply_each(&self.children, |c, b| match c { + HeaderChild::Paragraph(p) => b.add_child(&p), + HeaderChild::Table(t) => b.add_child(&t), + HeaderChild::StructuredDataTag(t) => b.add_child(&t), + })? + .close()? + .into_inner() } } @@ -109,8 +112,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" -"# + r#""# ); } } diff --git a/docx-core/src/documents/header_rels.rs b/docx-core/src/documents/header_rels.rs index 87b9e27..a6a3ec7 100644 --- a/docx-core/src/documents/header_rels.rs +++ b/docx-core/src/documents/header_rels.rs @@ -1,6 +1,7 @@ use crate::documents::BuildXML; use crate::{xml_builder::*, ImageIdAndPath}; use serde::Serialize; +use std::io::Write; #[derive(Debug, Clone, PartialEq, Serialize, Default)] #[serde(rename_all = "camelCase")] @@ -24,20 +25,21 @@ impl HeaderRels { } impl BuildXML for HeaderRels { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new(); - b = b - .declaration(None) - .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships"); - - for (id, path) in self.images.iter() { - b = b.relationship( - id, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - path, - ) - } - - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(None)? + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")? + .apply_each(&self.images, |(id, path), b| { + b.relationship( + id, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + path, + ) + })? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/mod.rs b/docx-core/src/documents/mod.rs index 74c30e6..7be938e 100644 --- a/docx-core/src/documents/mod.rs +++ b/docx-core/src/documents/mod.rs @@ -40,7 +40,7 @@ mod web_settings; mod webextension; mod xml_docx; -pub(crate) use build_xml::BuildXML; +pub use build_xml::BuildXML; pub(crate) use history_id::HistoryId; pub(crate) use hyperlink_id::*; pub(crate) use paragraph_id::*; diff --git a/docx-core/src/documents/numberings.rs b/docx-core/src/documents/numberings.rs index 40e1fd7..64f8dcf 100644 --- a/docx-core/src/documents/numberings.rs +++ b/docx-core/src/documents/numberings.rs @@ -2,6 +2,7 @@ use super::*; use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; +use std::io::Write; use serde::Serialize; @@ -29,17 +30,19 @@ impl Numberings { } impl BuildXML for Numberings { - fn build(&self) -> Vec { - let mut b = XMLBuilder::new().declaration(Some(true)).open_numbering(); - b = b.add_child(&create_default_numbering()); - for n in &self.abstract_nums { - b = b.add_child(n); - } - b = b.add_child(&Numbering::new(1, 1)); - for n in &self.numberings { - b = b.add_child(n); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_numbering()? + .add_child(&create_default_numbering())? + .add_children(&self.abstract_nums)? + .add_child(&Numbering::new(1, 1))? + .add_children(&self.numberings)? + .close()? + .into_inner() } } diff --git a/docx-core/src/documents/rels.rs b/docx-core/src/documents/rels.rs index caa37f6..2ba1ac2 100644 --- a/docx-core/src/documents/rels.rs +++ b/docx-core/src/documents/rels.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -62,15 +63,16 @@ impl Rels { } impl BuildXML for Rels { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b - .declaration(None) - .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships"); - for (k, id, v) in self.rels.iter() { - b = b.relationship(id, k, v); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(None)? + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")? + .apply_each(&self.rels, |(k, id, v), b| b.relationship(id, k, v))? + .close()? + .into_inner() } } @@ -88,13 +90,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/settings.rs b/docx-core/src/documents/settings.rs index 611ec69..17bd6ea 100644 --- a/docx-core/src/documents/settings.rs +++ b/docx-core/src/documents/settings.rs @@ -1,4 +1,5 @@ use super::*; +use std::io::Write; use crate::documents::BuildXML; use crate::types::CharacterSpacingValues; @@ -70,82 +71,72 @@ impl Default for Settings { } impl BuildXML for Settings { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b - .declaration(Some(true)) - .open_settings() - .add_child(&self.default_tab_stop) - .add_child(&self.zoom) - .open_compat() - .space_for_ul() - .balance_single_byte_double_byte_width() - .do_not_leave_backslash_alone() - .ul_trail_space() - .do_not_expand_shift_return(); - - if let Some(v) = self.character_spacing_control { - b = b.character_spacing_control(&v.to_string()); - } - - if self.adjust_line_height_in_table { - b = b.adjust_line_height_table(); - } - - b = b - .use_fe_layout() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_settings()? + .add_child(&self.default_tab_stop)? + .add_child(&self.zoom)? + .open_compat()? + .space_for_ul()? + .balance_single_byte_double_byte_width()? + .do_not_leave_backslash_alone()? + .ul_trail_space()? + .do_not_expand_shift_return()? + .apply_opt(self.character_spacing_control, |v, b| { + b.character_spacing_control(&v.to_string()) + })? + .apply_if(self.adjust_line_height_in_table, |b| { + b.adjust_line_height_table() + })? + .use_fe_layout()? .compat_setting( "compatibilityMode", "http://schemas.microsoft.com/office/word", "15", - ) + )? .compat_setting( "overrideTableStyleFontSizeAndJustification", "http://schemas.microsoft.com/office/word", "1", - ) + )? .compat_setting( "enableOpenTypeFeatures", "http://schemas.microsoft.com/office/word", "1", - ) + )? .compat_setting( "doNotFlipMirrorIndents", "http://schemas.microsoft.com/office/word", "1", - ) + )? .compat_setting( "differentiateMultirowTableHeaders", "http://schemas.microsoft.com/office/word", "1", - ) + )? .compat_setting( "useWord2013TrackBottomHyphenation", "http://schemas.microsoft.com/office/word", "0", - ) - .close() - .add_optional_child(&self.doc_id); - - if !self.doc_vars.is_empty() { - b = b.open_doc_vars(); - for v in self.doc_vars.iter() { - b = b.add_child(v); - } - b = b.close(); - } - - if self.even_and_odd_headers { - b = b.even_and_odd_headers(); - } - b.close().build() + )? + .close()? + .add_optional_child(&self.doc_id)? + .apply_if(!self.doc_vars.is_empty(), |b| { + b.open_doc_vars()?.add_children(&self.doc_vars)?.close() + })? + .apply_if(self.even_and_odd_headers, |b| b.even_and_odd_headers())? + .close()? + .into_inner() } } #[cfg(test)] mod tests { use super::*; - #[cfg(test)] use pretty_assertions::assert_eq; use std::str; @@ -155,22 +146,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - - - - - - - - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/styles.rs b/docx-core/src/documents/styles.rs index 0bc3f2c..ee496b0 100644 --- a/docx-core/src/documents/styles.rs +++ b/docx-core/src/documents/styles.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use super::*; use crate::documents::BuildXML; @@ -76,15 +77,18 @@ impl Default for Styles { } impl BuildXML for Styles { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { let normal = Style::new("Normal", StyleType::Paragraph).name("Normal"); - b.open_styles() - .add_child(&self.doc_defaults) - .add_child(&normal) - .add_children(&self.styles) - .close() - .build() + XMLBuilder::from(stream) + .open_styles()? + .add_child(&self.doc_defaults)? + .add_child(&normal)? + .add_children(&self.styles)? + .close()? + .into_inner() } } @@ -124,12 +128,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - -"# + r#""# ); } diff --git a/docx-core/src/documents/taskpanes.rs b/docx-core/src/documents/taskpanes.rs index 1975a44..3dcfb17 100644 --- a/docx-core/src/documents/taskpanes.rs +++ b/docx-core/src/documents/taskpanes.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -13,19 +14,21 @@ impl Taskpanes { } impl BuildXML for Taskpanes { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let b = b - .declaration(Some(true)) - .open_taskpanes("http://schemas.microsoft.com/office/webextensions/taskpanes/2010/11") - .open_taskpane("", "1", "350", "1") + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_taskpanes("http://schemas.microsoft.com/office/webextensions/taskpanes/2010/11")? + .open_taskpane("", "1", "350", "1")? .webextensionref( "http://schemas.openxmlformats.org/officeDocument/2006/relationships", "rId1", - ) - .close() - .close(); - b.build() + )? + .close()? + .close()? + .into_inner() } } @@ -43,12 +46,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/taskpanes_rels.rs b/docx-core/src/documents/taskpanes_rels.rs index b87959e..457e28a 100644 --- a/docx-core/src/documents/taskpanes_rels.rs +++ b/docx-core/src/documents/taskpanes_rels.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::io::Write; use crate::documents::BuildXML; use crate::xml_builder::*; @@ -29,15 +30,16 @@ impl TaskpanesRels { } impl BuildXML for TaskpanesRels { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b - .declaration(Some(true)) - .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships"); - for (k, id, v) in self.rels.iter() { - b = b.relationship(id, k, v); - } - b.close().build() + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")? + .apply_each(&self.rels, |(k, id, v), b| b.relationship(id, k, v))? + .close()? + .into_inner() } } @@ -55,10 +57,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - -"# + r#""# ); } } diff --git a/docx-core/src/documents/webextension.rs b/docx-core/src/documents/webextension.rs index 8341ca0..34c56f9 100644 --- a/docx-core/src/documents/webextension.rs +++ b/docx-core/src/documents/webextension.rs @@ -1,4 +1,5 @@ use serde::Serialize; +use std::io::Write; use crate::documents::BuildXML; use crate::escape::escape; @@ -50,40 +51,40 @@ impl WebExtension { pub fn property(mut self, name: impl Into, value: impl Into) -> Self { let v = value.into(); let v = format!(""{}"", escape(&v).replace(""", "\\"")); - self.properties.push(WebExtensionProperty::new(name, &v)); + self.properties.push(WebExtensionProperty::new(name, v)); self } } impl BuildXML for WebExtension { - fn build(&self) -> Vec { - let b = XMLBuilder::new(); - let mut b = b - .declaration(Some(true)) + fn build_to( + &self, + stream: xml::writer::EventWriter, + ) -> xml::writer::Result> { + XMLBuilder::from(stream) + .declaration(Some(true))? .open_webextension( "http://schemas.microsoft.com/office/webextensions/webextension/2010/11", &format!("{{{}}}", &self.id), - ) + )? .webextension_reference( &self.reference_id, &self.version, &self.store, &self.store_type, - ) - .webextension_alternate_references() - .open_webextension_properties(); - - for p in self.properties.iter() { - b = b.webextension_property(&p.name, &p.value); - } - - b.close() - .webextension_bindings() + )? + .webextension_alternate_references()? + .open_webextension_properties()? + .apply_each(&self.properties, |p, b| { + b.webextension_property(&p.name, &p.value) + })? + .close()? + .webextension_bindings()? .webextension_snapshot( "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .close() - .build() + )? + .close()? + .into_inner() } } @@ -108,16 +109,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" - - - - - - - - -"# + r#""# ); } } diff --git a/docx-core/src/reader/attributes/width.rs b/docx-core/src/reader/attributes/width.rs index 8ec3d6d..617e52c 100644 --- a/docx-core/src/reader/attributes/width.rs +++ b/docx-core/src/reader/attributes/width.rs @@ -14,7 +14,7 @@ pub fn read_width(attrs: &[OwnedAttribute]) -> Result<(isize, WidthType), Reader if local_name == "type" { width_type = WidthType::from_str(&a.value)?; } else if local_name == "w" { - let v = a.value.replace("%", ""); + let v = a.value.replace('%', ""); w = f64::from_str(&v).expect("should read width.") as isize; } } diff --git a/docx-core/src/reader/comment.rs b/docx-core/src/reader/comment.rs index 46fe71b..b8c5304 100644 --- a/docx-core/src/reader/comment.rs +++ b/docx-core/src/reader/comment.rs @@ -4,8 +4,8 @@ use std::str::FromStr; use xml::attribute::OwnedAttribute; use xml::reader::{EventReader, XmlEvent}; -use crate::escape; use super::*; +use crate::escape; impl ElementReader for Comment { fn read( diff --git a/docx-core/src/reader/settings.rs b/docx-core/src/reader/settings.rs index 52f19f4..dbb8ba4 100644 --- a/docx-core/src/reader/settings.rs +++ b/docx-core/src/reader/settings.rs @@ -25,9 +25,8 @@ impl FromXML for Settings { let local_name = &a.name.local_name; // Ignore w14:val if local_name == "val" && prefix == "w15" { - settings = settings.doc_id( - a.value.to_owned().replace("{", "").replace("}", ""), - ); + settings = settings + .doc_id(a.value.to_owned().replace(['{', '}'], "")); } } } diff --git a/docx-core/src/types/character_spacing_values.rs b/docx-core/src/types/character_spacing_values.rs index af277e7..b9a51d2 100644 --- a/docx-core/src/types/character_spacing_values.rs +++ b/docx-core/src/types/character_spacing_values.rs @@ -3,8 +3,8 @@ use std::str::FromStr; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; -use serde::{Serialize, Deserialize}; use super::errors; +use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "wasm", wasm_bindgen)] #[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -21,7 +21,9 @@ impl fmt::Display for CharacterSpacingValues { match *self { CharacterSpacingValues::DoNotCompress => write!(f, "doNotCompress"), CharacterSpacingValues::CompressPunctuation => write!(f, "compressPunctuation"), - CharacterSpacingValues::CompressPunctuationAndJapaneseKana => write!(f, "compressPunctuationAndJapaneseKana"), + CharacterSpacingValues::CompressPunctuationAndJapaneseKana => { + write!(f, "compressPunctuationAndJapaneseKana") + } _ => write!(f, "unsupported"), } } @@ -33,8 +35,10 @@ impl FromStr for CharacterSpacingValues { match s { "doNotCompress" => Ok(CharacterSpacingValues::DoNotCompress), "compressPunctuation" => Ok(CharacterSpacingValues::CompressPunctuation), - "compressPunctuationAndJapaneseKana" => Ok(CharacterSpacingValues::CompressPunctuationAndJapaneseKana), - _ => Err(errors::TypeError::Unsupported(s.to_string())) + "compressPunctuationAndJapaneseKana" => { + Ok(CharacterSpacingValues::CompressPunctuationAndJapaneseKana) + } + _ => Err(errors::TypeError::Unsupported(s.to_string())), } } } diff --git a/docx-core/src/xml_builder/comments.rs b/docx-core/src/xml_builder/comments.rs index 31a2a3d..355ba81 100644 --- a/docx-core/src/xml_builder/comments.rs +++ b/docx-core/src/xml_builder/comments.rs @@ -1,49 +1,48 @@ use super::XMLBuilder; use super::XmlEvent; +use std::io::Write; +use xml::writer::Result; -impl XMLBuilder { - pub(crate) fn open_comments(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:comments") - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") - .attr( - "xmlns:wp", - "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", - ) - .attr( - "xmlns:wps", - "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", - ) - .attr( - "xmlns:wpg", - "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", - ) - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:wp14", - "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr("mc:Ignorable", "w14 wp14"), - ) - .expect("should write to buf"); - self +impl XMLBuilder { + pub(crate) fn open_comments(self) -> Result { + self.write( + XmlEvent::start_element("w:comments") + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") + .attr( + "xmlns:wp", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + ) + .attr( + "xmlns:wps", + "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + ) + .attr( + "xmlns:wpg", + "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + ) + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:wp14", + "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr("mc:Ignorable", "w14 wp14"), + ) } } diff --git a/docx-core/src/xml_builder/comments_extended.rs b/docx-core/src/xml_builder/comments_extended.rs index 2df4c4a..64fa47e 100644 --- a/docx-core/src/xml_builder/comments_extended.rs +++ b/docx-core/src/xml_builder/comments_extended.rs @@ -1,125 +1,124 @@ use super::XMLBuilder; use super::XmlEvent; +use std::io::Write; +use xml::writer::Result; -impl XMLBuilder { - pub(crate) fn open_comments_extended(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w15:commentsEx") - .attr( - "xmlns:wpc", - "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", - ) - .attr( - "xmlns:cx", - "http://schemas.microsoft.com/office/drawing/2014/chartex", - ) - .attr( - "xmlns:cx1", - "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex", - ) - .attr( - "xmlns:cx2", - "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex", - ) - .attr( - "xmlns:cx3", - "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex", - ) - .attr( - "xmlns:cx4", - "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex", - ) - .attr( - "xmlns:cx5", - "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex", - ) - .attr( - "xmlns:cx6", - "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex", - ) - .attr( - "xmlns:cx7", - "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex", - ) - .attr( - "xmlns:cx8", - "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex", - ) - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:aink", - "http://schemas.microsoft.com/office/drawing/2016/ink", - ) - .attr( - "xmlns:am3d", - "http://schemas.microsoft.com/office/drawing/2017/model3d", - ) - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr( - "xmlns:m", - "http://schemas.openxmlformats.org/officeDocument/2006/math", - ) - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:wp14", - "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", - ) - .attr( - "xmlns:wp", - "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", - ) - .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr( - "xmlns:w15", - "http://schemas.microsoft.com/office/word/2012/wordml", - ) - .attr( - "xmlns:w16cex", - "http://schemas.microsoft.com/office/word/2018/wordml/cex", - ) - .attr( - "xmlns:w16cid", - "http://schemas.microsoft.com/office/word/2016/wordml/cid", - ) - .attr( - "xmlns:w16", - "http://schemas.microsoft.com/office/word/2018/wordml", - ) - .attr( - "xmlns:w16se", - "http://schemas.microsoft.com/office/word/2015/wordml/symex", - ) - .attr( - "xmlns:wpg", - "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", - ) - .attr( - "xmlns:wpi", - "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", - ) - .attr( - "xmlns:wne", - "http://schemas.microsoft.com/office/word/2006/wordml", - ) - .attr("xmlns:wps", "http://schemas.microsoft.com/office/word/2010"), - ) - .expect("should write to buf"); - self +impl XMLBuilder { + pub(crate) fn open_comments_extended(self) -> Result { + self.write( + XmlEvent::start_element("w15:commentsEx") + .attr( + "xmlns:wpc", + "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", + ) + .attr( + "xmlns:cx", + "http://schemas.microsoft.com/office/drawing/2014/chartex", + ) + .attr( + "xmlns:cx1", + "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex", + ) + .attr( + "xmlns:cx2", + "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex", + ) + .attr( + "xmlns:cx3", + "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex", + ) + .attr( + "xmlns:cx4", + "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex", + ) + .attr( + "xmlns:cx5", + "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex", + ) + .attr( + "xmlns:cx6", + "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex", + ) + .attr( + "xmlns:cx7", + "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex", + ) + .attr( + "xmlns:cx8", + "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex", + ) + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:aink", + "http://schemas.microsoft.com/office/drawing/2016/ink", + ) + .attr( + "xmlns:am3d", + "http://schemas.microsoft.com/office/drawing/2017/model3d", + ) + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr( + "xmlns:m", + "http://schemas.openxmlformats.org/officeDocument/2006/math", + ) + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:wp14", + "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + ) + .attr( + "xmlns:wp", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + ) + .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr( + "xmlns:w15", + "http://schemas.microsoft.com/office/word/2012/wordml", + ) + .attr( + "xmlns:w16cex", + "http://schemas.microsoft.com/office/word/2018/wordml/cex", + ) + .attr( + "xmlns:w16cid", + "http://schemas.microsoft.com/office/word/2016/wordml/cid", + ) + .attr( + "xmlns:w16", + "http://schemas.microsoft.com/office/word/2018/wordml", + ) + .attr( + "xmlns:w16se", + "http://schemas.microsoft.com/office/word/2015/wordml/symex", + ) + .attr( + "xmlns:wpg", + "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + ) + .attr( + "xmlns:wpi", + "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", + ) + .attr( + "xmlns:wne", + "http://schemas.microsoft.com/office/word/2006/wordml", + ) + .attr("xmlns:wps", "http://schemas.microsoft.com/office/word/2010"), + ) } } diff --git a/docx-core/src/xml_builder/core_properties.rs b/docx-core/src/xml_builder/core_properties.rs index 906d2ff..6f45ac8 100644 --- a/docx-core/src/xml_builder/core_properties.rs +++ b/docx-core/src/xml_builder/core_properties.rs @@ -1,7 +1,8 @@ use super::XMLBuilder; use super::XmlEvent; +use std::io::Write; -impl XMLBuilder { +impl XMLBuilder { // i.e. open!( open_core_properties, diff --git a/docx-core/src/xml_builder/custom_properties.rs b/docx-core/src/xml_builder/custom_properties.rs index 7b8a76d..e4ab51c 100644 --- a/docx-core/src/xml_builder/custom_properties.rs +++ b/docx-core/src/xml_builder/custom_properties.rs @@ -1,7 +1,9 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { +use std::io::Write; + +impl XMLBuilder { open!(open_custom_properties, "Properties", "xmlns", "xmlns:vt"); open!(open_property, "property", "fmtid", "pid", "name"); closed_with_child!(lpwstr, "vt:lpwstr"); diff --git a/docx-core/src/xml_builder/declaration.rs b/docx-core/src/xml_builder/declaration.rs index 573005b..c797ccc 100644 --- a/docx-core/src/xml_builder/declaration.rs +++ b/docx-core/src/xml_builder/declaration.rs @@ -1,33 +1,32 @@ -use super::XMLBuilder; +use super::{XMLBuilder, XmlEvent}; +use std::io::Write; +use xml::writer::Result; -impl XMLBuilder { - // Build XML declaration - // i.e. - pub(crate) fn declaration(mut self, standalone: Option) -> Self { - self.writer - .write(super::XmlEvent::StartDocument { - version: super::XmlVersion::Version10, - encoding: Some("UTF-8"), - standalone, - }) - .expect("should write to buf"); - self +impl XMLBuilder { + /// Build XML declaration + /// i.e. `` + pub(crate) fn declaration(self, standalone: Option) -> Result { + self.write(XmlEvent::StartDocument { + version: super::XmlVersion::Version10, + encoding: Some("UTF-8"), + standalone, + }) } } #[cfg(test)] mod tests { - use super::*; use std::str; #[test] - fn test_declaration() { - let b = XMLBuilder::new(); - let r = b.declaration(None).build(); + fn test_declaration() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.declaration(None)?.into_inner()?.into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } } diff --git a/docx-core/src/xml_builder/document.rs b/docx-core/src/xml_builder/document.rs index 1173387..ab95026 100644 --- a/docx-core/src/xml_builder/document.rs +++ b/docx-core/src/xml_builder/document.rs @@ -1,55 +1,55 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { - // i.e. - pub(crate) fn open_document(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:document") - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") - .attr( - "xmlns:wp", - "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", - ) - .attr( - "xmlns:wps", - "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", - ) - .attr( - "xmlns:wpg", - "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", - ) - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:wp14", - "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr( - "xmlns:w15", - "http://schemas.microsoft.com/office/word/2012/wordml", - ) - .attr("mc:Ignorable", "w14 wp14"), - ) - .expect("should write to buf"); - self +use std::io::Write; +use xml::writer::Result; + +impl XMLBuilder { + /// i.e. `` + pub(crate) fn open_document(self) -> Result { + self.write( + XmlEvent::start_element("w:document") + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") + .attr( + "xmlns:wp", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + ) + .attr( + "xmlns:wps", + "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + ) + .attr( + "xmlns:wpg", + "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + ) + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:wp14", + "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr( + "xmlns:w15", + "http://schemas.microsoft.com/office/word/2012/wordml", + ) + .attr("mc:Ignorable", "w14 wp14"), + ) } } @@ -62,12 +62,13 @@ mod tests { use std::str; #[test] - fn test_document() { - let b = XMLBuilder::new(); - let r = b.open_document().close().build(); + fn test_document() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.open_document()?.close()?.into_inner()?.into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } } diff --git a/docx-core/src/xml_builder/drawing.rs b/docx-core/src/xml_builder/drawing.rs index e6476c0..18b2390 100644 --- a/docx-core/src/xml_builder/drawing.rs +++ b/docx-core/src/xml_builder/drawing.rs @@ -1,7 +1,9 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { +use std::io::Write; + +impl XMLBuilder { open!( open_wp_inline, "wp:inline", diff --git a/docx-core/src/xml_builder/elements.rs b/docx-core/src/xml_builder/elements.rs index f48e199..24b34f0 100644 --- a/docx-core/src/xml_builder/elements.rs +++ b/docx-core/src/xml_builder/elements.rs @@ -4,42 +4,39 @@ use crate::types::*; use crate::FrameProperty; use crate::TablePositionProperty; -const EXPECT_MESSAGE: &str = "should write buf"; +use std::io::Write; +use xml::writer::Result; -impl XMLBuilder { +impl XMLBuilder { // i.e. open!(open_body, "w:body"); // i.e. closed_with_str!(based_on, "w:basedOn"); // i.e. - pub(crate) fn text(mut self, text: &str, preserve_space: bool) -> Self { + pub(crate) fn text(self, text: &str, preserve_space: bool) -> Result { let space = if preserve_space { "preserve" } else { "default" }; - self.writer - .write(XmlEvent::start_element("w:t").attr("xml:space", space)) - .expect(EXPECT_MESSAGE); - self.writer.write(text).expect(EXPECT_MESSAGE); - self.close() + self.write(XmlEvent::start_element("w:t").attr("xml:space", space))? + .write(text)? + .close() } - pub(crate) fn snap_to_grid(mut self, v: bool) -> Self { + pub(crate) fn snap_to_grid(self, v: bool) -> Result { let v = if v { "true".to_string() } else { "false".to_string() }; - self.writer - .write(XmlEvent::start_element("w:snapToGrid").attr("w:val", &v)) - .expect(EXPECT_MESSAGE); - self.close() + self.write(XmlEvent::start_element("w:snapToGrid").attr("w:val", &v))? + .close() } #[allow(clippy::too_many_arguments)] pub(crate) fn run_fonts( - mut self, + self, ascii: Option<&String>, hi_ansi: Option<&String>, cs: Option<&String>, @@ -49,7 +46,7 @@ impl XMLBuilder { cs_theme: Option<&String>, east_asia_theme: Option<&String>, hint: Option<&String>, - ) -> Self { + ) -> Result { let mut w = XmlEvent::start_element("w:rFonts"); if let Some(ascii) = ascii { w = w.attr("w:ascii", ascii); @@ -78,30 +75,27 @@ impl XMLBuilder { if let Some(hint) = hint { w = w.attr("w:hint", hint); } - self.writer.write(w).expect(EXPECT_MESSAGE); - self.close() + self.write(w)?.close() } // i.e. - pub(crate) fn delete_text(mut self, text: &str, preserve_space: bool) -> Self { + pub(crate) fn delete_text(self, text: &str, preserve_space: bool) -> Result { let space = if preserve_space { "preserve" } else { "default" }; - self.writer - .write(XmlEvent::start_element("w:delText").attr("xml:space", space)) - .expect(EXPECT_MESSAGE); - self.writer.write(text).expect(EXPECT_MESSAGE); - self.close() + self.write(XmlEvent::start_element("w:delText").attr("xml:space", space))? + .write(text)? + .close() } pub(crate) fn data_binding( - mut self, + self, xpath: Option<&String>, prefix_mappings: Option<&String>, store_item_id: Option<&String>, - ) -> Self { + ) -> Result { let mut e = XmlEvent::start_element("w:dataBinding"); if let Some(xpath) = xpath { e = e.attr("w:xpath", xpath); @@ -112,16 +106,15 @@ impl XMLBuilder { if let Some(store_item_id) = store_item_id { e = e.attr("w:storeItemID", store_item_id); } - self.writer.write(e).expect(EXPECT_MESSAGE); - self.close() + self.write(e)?.close() } pub(crate) fn open_hyperlink( - mut self, + self, rid: Option<&String>, anchor: Option<&String>, history: Option, - ) -> Self { + ) -> Result { let mut e = XmlEvent::start_element("w:hyperlink"); let history = history.unwrap_or(1); if let Some(rid) = rid { @@ -132,8 +125,7 @@ impl XMLBuilder { } let s = format!("{}", history); e = e.attr("w:history", s.as_str()); - self.writer.write(e).expect(EXPECT_MESSAGE); - self + self.write(e) } // i.e. @@ -200,15 +192,12 @@ impl XMLBuilder { // Build w:style element // i.e. - pub(crate) fn open_style(mut self, style_type: StyleType, id: &str) -> Self { - self.writer - .write( - XmlEvent::start_element("w:style") - .attr("w:type", &style_type.to_string()) - .attr("w:styleId", id), - ) - .expect(EXPECT_MESSAGE); - self + pub(crate) fn open_style(self, style_type: StyleType, id: &str) -> Result { + self.write( + XmlEvent::start_element("w:style") + .attr("w:type", &style_type.to_string()) + .attr("w:styleId", id), + ) } // i.e. closed_with_str!(next, "w:next"); @@ -228,12 +217,12 @@ impl XMLBuilder { // i.e. pub(crate) fn indent( - mut self, + self, start: Option, special_indent: Option, end: i32, start_chars: Option, - ) -> Self { + ) -> Result { let start = &format!("{}", start.unwrap_or(0)); let end = &format!("{}", end); let start_chars_value = format!("{}", start_chars.unwrap_or(0)); @@ -246,37 +235,33 @@ impl XMLBuilder { } match special_indent { - Some(SpecialIndentType::FirstLine(v)) => self - .writer - .write(base.attr("w:firstLine", &format!("{}", v))) - .expect(EXPECT_MESSAGE), - Some(SpecialIndentType::Hanging(v)) => self - .writer - .write(base.attr("w:hanging", &format!("{}", v))) - .expect(EXPECT_MESSAGE), - _ => self.writer.write(base).expect(EXPECT_MESSAGE), - }; - self.close() + Some(SpecialIndentType::FirstLine(v)) => { + self.write(base.attr("w:firstLine", &format!("{}", v))) + } + Some(SpecialIndentType::Hanging(v)) => { + self.write(base.attr("w:hanging", &format!("{}", v))) + } + None => self.write(base), + }? + .close() } // i.e. - pub(crate) fn spacing(mut self, s: i32) -> Self { - self.writer - .write(XmlEvent::start_element("w:spacing").attr("w:val", &format!("{}", s))) - .expect(EXPECT_MESSAGE); - self.close() + pub(crate) fn spacing(self, s: i32) -> Result { + self.write(XmlEvent::start_element("w:spacing").attr("w:val", &format!("{}", s)))? + .close() } // i.e. pub(crate) fn line_spacing( - mut self, + self, before: Option, after: Option, line: Option, before_lines: Option, after_lines: Option, spacing: Option, - ) -> Self { + ) -> Result { let mut xml_event = XmlEvent::start_element("w:spacing"); let before_val: String; let after_val: String; @@ -317,8 +302,7 @@ impl XMLBuilder { } } } - self.writer.write(xml_event).expect(EXPECT_MESSAGE); - self.close() + self.write(xml_event)?.close() } // @@ -540,39 +524,31 @@ impl XMLBuilder { // CommentExtended // w15:commentEx w15:paraId="00000001" w15:paraIdParent="57D1BD7C" w15:done="0" pub(crate) fn comment_extended( - mut self, + self, paragraph_id: &str, done: bool, parent_paragraph_id: &Option, - ) -> Self { - if let Some(parent_paragraph_id) = parent_paragraph_id { - self.writer - .write( - XmlEvent::start_element("w15:commentEx") - .attr("w15:paraId", paragraph_id) - .attr("w15:paraIdParent", parent_paragraph_id) - .attr("w15:done", &format!("{}", done as usize)), - ) - .expect(EXPECT_MESSAGE); - return self.close(); - } - self.writer - .write( - XmlEvent::start_element("w15:commentEx") - .attr("w15:paraId", paragraph_id) - .attr("w15:done", &format!("{}", done as usize)), - ) - .expect(EXPECT_MESSAGE); - self.close() + ) -> Result { + let done = format!("{}", done as usize); + let el = match parent_paragraph_id { + Some(parent_paragraph_id) => XmlEvent::start_element("w15:commentEx") + .attr("w15:paraId", paragraph_id) + .attr("w15:paraIdParent", parent_paragraph_id) + .attr("w15:done", &done), + None => XmlEvent::start_element("w15:commentEx") + .attr("w15:paraId", paragraph_id) + .attr("w15:done", &done), + }; + self.write(el)?.close() } // docGrid pub(crate) fn doc_grid( - mut self, + self, t: &DocGridType, line_pitch: Option, char_space: Option, - ) -> Self { + ) -> Result { let t = t.to_string(); let line_pitch_string = format!("{}", line_pitch.unwrap_or_default()); let char_space_string = format!("{}", char_space.unwrap_or_default()); @@ -583,9 +559,7 @@ impl XMLBuilder { if char_space.is_some() { w = w.attr("w:charSpace", &char_space_string); } - self.writer.write(w).expect(EXPECT_MESSAGE); - - self.close() + self.write(w)?.close() } /** @@ -593,7 +567,7 @@ impl XMLBuilder { pub v_space: Option, */ - pub(crate) fn frame_property(mut self, prop: &FrameProperty) -> Self { + pub(crate) fn frame_property(self, prop: &FrameProperty) -> Result { let mut w = XmlEvent::start_element("w:framePr"); let wrap: String = prop.wrap.iter().cloned().collect(); if prop.wrap.is_some() { @@ -643,11 +617,10 @@ impl XMLBuilder { if prop.h.is_some() { w = w.attr("w:h", &h); } - self.writer.write(w).expect(EXPECT_MESSAGE); - self.close() + self.write(w)?.close() } - pub(crate) fn table_position_property(mut self, prop: &TablePositionProperty) -> Self { + pub(crate) fn table_position_property(self, prop: &TablePositionProperty) -> Result { let mut w = XmlEvent::start_element("w:tblpPr"); let v: String = format!("{}", prop.left_from_text.unwrap_or_default()); @@ -690,11 +663,14 @@ impl XMLBuilder { w = w.attr("w:tblpY", &v); } - self.writer.write(w).expect(EXPECT_MESSAGE); - self.close() + self.write(w)?.close() } - pub(crate) fn page_num_type(mut self, start: Option, chap_style: Option) -> Self { + pub(crate) fn page_num_type( + self, + start: Option, + chap_style: Option, + ) -> Result { let mut w = XmlEvent::start_element("w:pgNumType"); let start_string = format!("{}", start.unwrap_or_default()); let chap_style_string = chap_style.clone().unwrap_or_default(); @@ -704,16 +680,15 @@ impl XMLBuilder { if chap_style.is_some() { w = w.attr("w:chapStyle", &chap_style_string); } - self.writer.write(w).expect(EXPECT_MESSAGE); - self.close() + self.write(w)?.close() } pub(crate) fn tab( - mut self, + self, v: Option, leader: Option, pos: Option, - ) -> Self { + ) -> Result { let v_string = if let Some(v) = v { v.to_string() } else { @@ -740,17 +715,15 @@ impl XMLBuilder { if pos.is_some() { t = t.attr("w:pos", &pos_string); } - self.writer.write(t).expect(EXPECT_MESSAGE); - - self.close() + self.write(t)?.close() } pub(crate) fn ptab( - mut self, + self, alignment: PositionalTabAlignmentType, relative_to: PositionalTabRelativeTo, leader: TabLeaderType, - ) -> Self { + ) -> Result { let alignment_string = alignment.to_string(); let relative_to_string = relative_to.to_string(); let leader_string = leader.to_string(); @@ -761,18 +734,14 @@ impl XMLBuilder { t = t.attr("w:relativeTo", &relative_to_string); t = t.attr("w:leader", &leader_string); - self.writer.write(t).expect(EXPECT_MESSAGE); - - self.close() + self.write(t)?.close() } // FootnoteReference // w:footnoteReference w:id="1" - pub(crate) fn footnote_reference(mut self, id: usize) -> Self { - self.writer - .write(XmlEvent::start_element("w:footnoteReference").attr("w:id", &id.to_string())) - .expect(EXPECT_MESSAGE); - self.close() + pub(crate) fn footnote_reference(self, id: usize) -> Result { + self.write(XmlEvent::start_element("w:footnoteReference").attr("w:id", &id.to_string()))? + .close() } // Footnotes @@ -787,79 +756,89 @@ mod tests { use std::str; #[test] - fn test_sz() { - let b = XMLBuilder::new(); - let r = b.sz(20).build(); + fn test_sz() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.sz(20)?.into_inner()?.into_inner(); assert_eq!(str::from_utf8(&r).unwrap(), r#""#); + Ok(()) } #[test] - fn test_declaration() { - let b = XMLBuilder::new(); + fn test_declaration() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); let r = b - .open_style(StyleType::Paragraph, "Heading") - .close() - .build(); + .open_style(StyleType::Paragraph, "Heading")? + .close()? + .into_inner()? + .into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } #[test] - fn test_next() { - let b = XMLBuilder::new(); - let r = b.next("Normal").build(); + fn test_next() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.next("Normal")?.into_inner()?.into_inner(); assert_eq!(str::from_utf8(&r).unwrap(), r#""#); + Ok(()) } #[test] - fn test_name() { - let b = XMLBuilder::new(); - let r = b.name("Heading").build(); + fn test_name() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.name("Heading")?.into_inner()?.into_inner(); assert_eq!(str::from_utf8(&r).unwrap(), r#""#); + Ok(()) } #[test] - fn test_color() { - let b = XMLBuilder::new(); - let r = b.color("2E74B5").build(); + fn test_color() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.color("2E74B5")?.into_inner()?.into_inner(); assert_eq!(str::from_utf8(&r).unwrap(), r#""#); + Ok(()) } #[test] - fn test_based_on() { - let b = XMLBuilder::new(); - let r = b.based_on("Normal").build(); + fn test_based_on() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.based_on("Normal")?.into_inner()?.into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } #[test] - fn test_ptab() { - let b = XMLBuilder::new(); + fn test_ptab() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); let r = b .ptab( PositionalTabAlignmentType::Left, PositionalTabRelativeTo::Indent, TabLeaderType::None, - ) - .build(); + )? + .into_inner()? + .into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } #[test] - fn test_footnote_reference() { - let b = XMLBuilder::new(); - let r = b.footnote_reference(1).build(); + fn test_footnote_reference() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.footnote_reference(1)?.into_inner()?.into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } } diff --git a/docx-core/src/xml_builder/fonts.rs b/docx-core/src/xml_builder/fonts.rs index df508de..c9e67e6 100644 --- a/docx-core/src/xml_builder/fonts.rs +++ b/docx-core/src/xml_builder/fonts.rs @@ -1,21 +1,21 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { - pub(crate) fn open_fonts(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:fonts") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ), - ) - .expect("should write to buf"); - self +use std::io::Write; +use xml::writer::Result; + +impl XMLBuilder { + pub(crate) fn open_fonts(self) -> Result { + self.write( + XmlEvent::start_element("w:fonts") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ), + ) } } diff --git a/docx-core/src/xml_builder/footer.rs b/docx-core/src/xml_builder/footer.rs index dfc77ac..04aa170 100644 --- a/docx-core/src/xml_builder/footer.rs +++ b/docx-core/src/xml_builder/footer.rs @@ -1,49 +1,49 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { - pub(crate) fn open_footer(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:ftr") - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") - .attr( - "xmlns:wp", - "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", - ) - .attr( - "xmlns:wps", - "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", - ) - .attr( - "xmlns:wpg", - "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", - ) - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:wp14", - "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr("mc:Ignorable", "w14 wp14"), - ) - .expect("should write to buf"); - self +use std::io::Write; +use xml::writer::Result; + +impl XMLBuilder { + pub(crate) fn open_footer(self) -> Result { + self.write( + XmlEvent::start_element("w:ftr") + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") + .attr( + "xmlns:wp", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + ) + .attr( + "xmlns:wps", + "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + ) + .attr( + "xmlns:wpg", + "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + ) + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:wp14", + "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr("mc:Ignorable", "w14 wp14"), + ) } } diff --git a/docx-core/src/xml_builder/footnotes.rs b/docx-core/src/xml_builder/footnotes.rs index 03f744b..59f56ff 100644 --- a/docx-core/src/xml_builder/footnotes.rs +++ b/docx-core/src/xml_builder/footnotes.rs @@ -1,144 +1,144 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { - pub(crate) fn open_footnotes(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:footnotes") - .attr( - "xmlns:wpc", - "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", - ) - .attr( - "xmlns:cx", - "http://schemas.microsoft.com/office/drawing/2014/chartex", - ) - .attr( - "xmlns:cx1", - "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex", - ) - .attr( - "xmlns:cx2", - "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex", - ) - .attr( - "xmlns:cx3", - "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex", - ) - .attr( - "xmlns:cx4", - "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex", - ) - .attr( - "xmlns:cx5", - "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex", - ) - .attr( - "xmlns:cx6", - "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex", - ) - .attr( - "xmlns:cx7", - "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex", - ) - .attr( - "xmlns:cx8", - "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex", - ) - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:aink", - "http://schemas.microsoft.com/office/drawing/2016/ink", - ) - .attr( - "xmlns:am3d", - "http://schemas.microsoft.com/office/drawing/2017/model3d", - ) - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr( - "xmlns:oel", - "http://schemas.microsoft.com/office/2019/extlst", - ) - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr( - "xmlns:m", - "http://schemas.openxmlformats.org/officeDocument/2006/math", - ) - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:wp14", - "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", - ) - .attr( - "xmlns:wp", - "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", - ) - .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr( - "xmlns:w15", - "http://schemas.microsoft.com/office/word/2012/wordml", - ) - .attr( - "xmlns:w16cex", - "http://schemas.microsoft.com/office/word/2018/wordml/cex", - ) - .attr( - "xmlns:w16cid", - "http://schemas.microsoft.com/office/word/2016/wordml/cid", - ) - .attr( - "xmlns:w16", - "http://schemas.microsoft.com/office/word/2018/wordml", - ) - .attr( - "xmlns:w16du", - "http://schemas.microsoft.com/office/word/2023/wordml/word16du", - ) - .attr( - "xmlns:w16sdtdh", - "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash", - ) - .attr( - "xmlns:w16se", - "http://schemas.microsoft.com/office/word/2015/wordml/symex", - ) - .attr( - "xmlns:wpg", - "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", - ) - .attr( - "xmlns:wpi", - "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", - ) - .attr( - "xmlns:wne", - "http://schemas.microsoft.com/office/word/2006/wordml", - ) - .attr( - "xmlns:wps", - "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", - ) - .attr( - "mc:Ignorable", - "w14 w15 w16se w16cid w16 w16cex w16sdtdh w16du wp14", - ), - ) - .expect("should write to buf"); - self +use std::io::Write; +use xml::writer::Result; + +impl XMLBuilder { + pub(crate) fn open_footnotes(self) -> Result { + self.write( + XmlEvent::start_element("w:footnotes") + .attr( + "xmlns:wpc", + "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", + ) + .attr( + "xmlns:cx", + "http://schemas.microsoft.com/office/drawing/2014/chartex", + ) + .attr( + "xmlns:cx1", + "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex", + ) + .attr( + "xmlns:cx2", + "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex", + ) + .attr( + "xmlns:cx3", + "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex", + ) + .attr( + "xmlns:cx4", + "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex", + ) + .attr( + "xmlns:cx5", + "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex", + ) + .attr( + "xmlns:cx6", + "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex", + ) + .attr( + "xmlns:cx7", + "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex", + ) + .attr( + "xmlns:cx8", + "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex", + ) + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:aink", + "http://schemas.microsoft.com/office/drawing/2016/ink", + ) + .attr( + "xmlns:am3d", + "http://schemas.microsoft.com/office/drawing/2017/model3d", + ) + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr( + "xmlns:oel", + "http://schemas.microsoft.com/office/2019/extlst", + ) + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr( + "xmlns:m", + "http://schemas.openxmlformats.org/officeDocument/2006/math", + ) + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:wp14", + "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + ) + .attr( + "xmlns:wp", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + ) + .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr( + "xmlns:w15", + "http://schemas.microsoft.com/office/word/2012/wordml", + ) + .attr( + "xmlns:w16cex", + "http://schemas.microsoft.com/office/word/2018/wordml/cex", + ) + .attr( + "xmlns:w16cid", + "http://schemas.microsoft.com/office/word/2016/wordml/cid", + ) + .attr( + "xmlns:w16", + "http://schemas.microsoft.com/office/word/2018/wordml", + ) + .attr( + "xmlns:w16du", + "http://schemas.microsoft.com/office/word/2023/wordml/word16du", + ) + .attr( + "xmlns:w16sdtdh", + "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash", + ) + .attr( + "xmlns:w16se", + "http://schemas.microsoft.com/office/word/2015/wordml/symex", + ) + .attr( + "xmlns:wpg", + "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + ) + .attr( + "xmlns:wpi", + "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", + ) + .attr( + "xmlns:wne", + "http://schemas.microsoft.com/office/word/2006/wordml", + ) + .attr( + "xmlns:wps", + "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + ) + .attr( + "mc:Ignorable", + "w14 w15 w16se w16cid w16 w16cex w16sdtdh w16du wp14", + ), + ) } } diff --git a/docx-core/src/xml_builder/header.rs b/docx-core/src/xml_builder/header.rs index b27a918..2f44be9 100644 --- a/docx-core/src/xml_builder/header.rs +++ b/docx-core/src/xml_builder/header.rs @@ -1,49 +1,49 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { - pub(crate) fn open_header(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:hdr") - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") - .attr( - "xmlns:wp", - "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", - ) - .attr( - "xmlns:wps", - "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", - ) - .attr( - "xmlns:wpg", - "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", - ) - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:wp14", - "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr("mc:Ignorable", "w14 wp14"), - ) - .expect("should write to buf"); - self +use std::io::Write; +use xml::writer::Result; + +impl XMLBuilder { + pub(crate) fn open_header(self) -> Result { + self.write( + XmlEvent::start_element("w:hdr") + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr("xmlns:w10", "urn:schemas-microsoft-com:office:word") + .attr( + "xmlns:wp", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + ) + .attr( + "xmlns:wps", + "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", + ) + .attr( + "xmlns:wpg", + "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + ) + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:wp14", + "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr("mc:Ignorable", "w14 wp14"), + ) } } diff --git a/docx-core/src/xml_builder/macros.rs b/docx-core/src/xml_builder/macros.rs index fe97d26..bacf1ba 100644 --- a/docx-core/src/xml_builder/macros.rs +++ b/docx-core/src/xml_builder/macros.rs @@ -1,109 +1,99 @@ macro_rules! open { ($name: ident, $el_name: expr) => { #[allow(dead_code)] - pub(crate) fn $name(mut self) -> Self { - self.writer - .write(XmlEvent::start_element($el_name)) - .expect("should write to buf"); - self + pub(crate) fn $name(self) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name)) } }; ($name: ident, $el_name: expr, $attr0: expr) => { - pub(crate) fn $name(mut self, arg0: &str) -> Self { - self.writer - .write(XmlEvent::start_element($el_name).attr($attr0, arg0)) - .expect("should write to buf"); - self + pub(crate) fn $name(self, arg0: &str) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name).attr($attr0, arg0)) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr) => { - pub(crate) fn $name(mut self, arg0: &str, arg1: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1), - ) - .expect("should write to buf"); - self + pub(crate) fn $name(self, arg0: &str, arg1: &str) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr) => { - pub(crate) fn $name(mut self, arg0: &str, arg1: &str, arg2: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2), - ) - .expect("should write to buf"); - self + pub(crate) fn $name( + self, + arg0: &str, + arg1: &str, + arg2: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr) => { - pub(crate) fn $name(mut self, arg0: &str, arg1: &str, arg2: &str, arg3: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3), - ) - .expect("should write to buf"); - self + pub(crate) fn $name( + self, + arg0: &str, + arg1: &str, + arg2: &str, + arg3: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, arg3: &str, arg4: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, arg3: &str, arg4: &str, arg5: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -111,25 +101,22 @@ macro_rules! open { arg4: &str, arg5: &str, arg6: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr, $attr7: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -138,26 +125,23 @@ macro_rules! open { arg5: &str, arg6: &str, arg7: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6) - .attr($attr7, arg7), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6) + .attr($attr7, arg7), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr, $attr7: expr, $attr8: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -167,28 +151,25 @@ macro_rules! open { arg6: &str, arg7: &str, arg8: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6) - .attr($attr7, arg7) - .attr($attr8, arg8), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6) + .attr($attr7, arg7) + .attr($attr8, arg8), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr, $attr7: expr, $attr8: expr, $attr9: expr) => { #[allow(clippy::too_many_arguments)] pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -199,28 +180,25 @@ macro_rules! open { arg7: &str, arg8: &str, arg9: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6) - .attr($attr7, arg7) - .attr($attr8, arg8) - .attr($attr9, arg9), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6) + .attr($attr7, arg7) + .attr($attr8, arg8) + .attr($attr9, arg9), + ) } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr, $attr7: expr, $attr8: expr, $attr9: expr, $attr10: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -232,24 +210,21 @@ macro_rules! open { arg8: &str, arg9: &str, arg10: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6) - .attr($attr7, arg7) - .attr($attr8, arg8) - .attr($attr9, arg9) - .attr($attr10, arg10), - ) - .expect("should write to buf"); - self + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6) + .attr($attr7, arg7) + .attr($attr8, arg8) + .attr($attr9, arg9) + .attr($attr10, arg10), + ) } }; } @@ -257,48 +232,51 @@ macro_rules! open { macro_rules! closed_with_child { ($name: ident, $el_name: expr) => { #[allow(dead_code)] - pub(crate) fn $name(mut self, child: &str) -> Self { - self.writer - .write(XmlEvent::start_element($el_name)) - .expect("should write to buf"); - self.writer.write(child).expect("should write to buf"); - self.close() + pub(crate) fn $name(self, child: &str) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name))? + .write(child)? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr) => { - pub(crate) fn $name(mut self, arg0: &str, child: &str) -> Self { - self.writer - .write(XmlEvent::start_element($el_name).attr($attr0, arg0)) - .expect("should write to buf"); - self.writer.write(child).expect("should write to buf"); - self.close() + pub(crate) fn $name(self, arg0: &str, child: &str) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name).attr($attr0, arg0))? + .write(child)? + .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( - 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() + pub(crate) fn $name( + self, + arg0: &str, + arg1: &str, + child: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1), + )? + .write(child)? + .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( - 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() + pub(crate) fn $name( + self, + arg0: &str, + arg1: &str, + arg2: &str, + child: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2), + )? + .write(child)? + .close() } }; } @@ -306,114 +284,110 @@ macro_rules! closed_with_child { macro_rules! closed { ($name: ident, $el_name: expr) => { #[allow(clippy::wrong_self_convention)] - pub(crate) fn $name(mut self) -> Self { - self.writer - .write(XmlEvent::start_element($el_name)) - .expect("should write to buf"); - self.close() + pub(crate) fn $name(self) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name))?.close() } }; ($name: ident, $el_name: expr, $attr0: expr) => { #[allow(clippy::wrong_self_convention)] - pub(crate) fn $name(mut self, arg0: &str) -> Self { - self.writer - .write(XmlEvent::start_element($el_name).attr($attr0, arg0)) - .expect("should write to buf"); - self.close() + pub(crate) fn $name(self, arg0: &str) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name).attr($attr0, arg0))? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr) => { #[allow(dead_code)] #[allow(clippy::wrong_self_convention)] - pub(crate) fn $name(mut self, arg0: &str, arg1: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1), - ) - .expect("should write to buf"); - self.close() + pub(crate) fn $name(self, arg0: &str, arg1: &str) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr) => { - pub(crate) fn $name(mut self, arg0: &str, arg1: &str, arg2: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2), - ) - .expect("should write to buf"); - self.close() + pub(crate) fn $name( + self, + arg0: &str, + arg1: &str, + arg2: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr) => { - pub(crate) fn $name(mut self, arg0: &str, arg1: &str, arg2: &str, arg3: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3), - ) - .expect("should write to buf"); - self.close() + pub(crate) fn $name( + self, + arg0: &str, + arg1: &str, + arg2: &str, + arg3: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, arg3: &str, arg4: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4), - ) - .expect("should write to buf"); - self.close() + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr) => { pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, arg3: &str, arg4: &str, arg5: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5), - ) - .expect("should write to buf"); - self.close() + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr) => { #[allow(clippy::too_many_arguments)] pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -421,26 +395,24 @@ macro_rules! closed { arg4: &str, arg5: &str, arg6: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6), - ) - .expect("should write to buf"); - self.close() + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr, $attr7: expr) => { #[allow(clippy::too_many_arguments)] pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -449,27 +421,25 @@ macro_rules! closed { arg5: &str, arg6: &str, arg7: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6) - .attr($attr7, arg7), - ) - .expect("should write to buf"); - self.close() + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6) + .attr($attr7, arg7), + )? + .close() } }; ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr, $attr3: expr, $attr4: expr, $attr5: expr, $attr6: expr, $attr7: expr, $attr8: expr) => { #[allow(clippy::too_many_arguments)] pub(crate) fn $name( - mut self, + self, arg0: &str, arg1: &str, arg2: &str, @@ -479,22 +449,20 @@ macro_rules! closed { arg6: &str, arg7: &str, arg8: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr($attr0, arg0) - .attr($attr1, arg1) - .attr($attr2, arg2) - .attr($attr3, arg3) - .attr($attr4, arg4) - .attr($attr5, arg5) - .attr($attr6, arg6) - .attr($attr7, arg7) - .attr($attr8, arg8), - ) - .expect("should write to buf"); - self.close() + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr($attr0, arg0) + .attr($attr1, arg1) + .attr($attr2, arg2) + .attr($attr3, arg3) + .attr($attr4, arg4) + .attr($attr5, arg5) + .attr($attr6, arg6) + .attr($attr7, arg7) + .attr($attr8, arg8), + )? + .close() } }; } @@ -502,48 +470,40 @@ macro_rules! closed { macro_rules! closed_with_str { ($name: ident, $el_name: expr) => { #[allow(dead_code)] - pub(crate) fn $name(mut self, val: &str) -> Self { - self.writer - .write(XmlEvent::start_element($el_name).attr("w:val", val)) - .expect("should write to buf"); - self.close() + pub(crate) fn $name(self, val: &str) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name).attr("w:val", val))? + .close() } }; } macro_rules! closed_with_usize { ($name: ident, $el_name: expr) => { - pub(crate) fn $name(mut self, val: usize) -> Self { - self.writer - .write(XmlEvent::start_element($el_name).attr("w:val", &format!("{}", val))) - .expect("should write to buf"); - self.close() + pub(crate) fn $name(self, val: usize) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name).attr("w:val", &format!("{}", val)))? + .close() } }; } macro_rules! closed_with_isize { ($name: ident, $el_name: expr) => { - pub(crate) fn $name(mut self, val: isize) -> Self { - self.writer - .write(XmlEvent::start_element($el_name).attr("w:val", &format!("{}", val))) - .expect("should write to buf"); - self.close() + pub(crate) fn $name(self, val: isize) -> ::xml::writer::Result { + self.write(XmlEvent::start_element($el_name).attr("w:val", &format!("{}", val)))? + .close() } }; } macro_rules! closed_w_with_type_el { ($name: ident, $el_name: expr) => { - pub(crate) fn $name(mut self, w: i32, t: WidthType) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr("w:w", &format!("{}", w)) - .attr("w:type", &t.to_string()), - ) - .expect(EXPECT_MESSAGE); - self.close() + pub(crate) fn $name(self, w: i32, t: WidthType) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr("w:w", &format!("{}", w)) + .attr("w:type", &t.to_string()), + )? + .close() } }; } @@ -551,39 +511,41 @@ macro_rules! closed_w_with_type_el { macro_rules! closed_border_el { ($name: ident, $el_name: expr) => { pub(crate) fn $name( - mut self, + self, val: BorderType, size: usize, space: usize, color: &str, - ) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr("w:val", &val.to_string()) - .attr("w:sz", &format!("{}", size)) - .attr("w:space", &format!("{}", space)) - .attr("w:color", color), - ) - .expect(EXPECT_MESSAGE); - self.close() + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr("w:val", &val.to_string()) + .attr("w:sz", &format!("{}", size)) + .attr("w:space", &format!("{}", space)) + .attr("w:color", color), + )? + .close() } }; } macro_rules! closed_paragraph_border_el { ($name: ident, $ el_name: expr) => { - pub(crate) fn $name(mut self, val: &str, space: &str, size: &str, color: &str) -> Self { - self.writer - .write( - XmlEvent::start_element($el_name) - .attr("w:val", val) - .attr("w:space", space) - .attr("w:sz", size) - .attr("w:color", color), - ) - .expect(EXPECT_MESSAGE); - self.close() + pub(crate) fn $name( + self, + val: &str, + space: &str, + size: &str, + color: &str, + ) -> ::xml::writer::Result { + self.write( + XmlEvent::start_element($el_name) + .attr("w:val", val) + .attr("w:space", space) + .attr("w:sz", size) + .attr("w:color", color), + )? + .close() } }; } diff --git a/docx-core/src/xml_builder/mod.rs b/docx-core/src/xml_builder/mod.rs index 7a8405b..357cfb0 100644 --- a/docx-core/src/xml_builder/mod.rs +++ b/docx-core/src/xml_builder/mod.rs @@ -23,111 +23,180 @@ mod styles; use crate::BuildXML; +use std::io::Write; use std::str; use xml::common::XmlVersion; -use xml::writer::{EmitterConfig, EventWriter, XmlEvent}; +use xml::writer::{EmitterConfig, EventWriter, Result, XmlEvent}; -pub struct XMLBuilder { - writer: EventWriter>, +pub use elements::*; + +pub struct XMLBuilder { + writer: EventWriter, } -impl XMLBuilder { - pub(crate) fn new() -> XMLBuilder { - let buf = Vec::new(); - let mut config = EmitterConfig::new() - .write_document_declaration(false) - .perform_indent(true); - config.perform_escaping = false; - let writer = config.create_writer(buf); +impl From> for XMLBuilder { + fn from(writer: EventWriter) -> Self { + Self { writer } + } +} + +impl XMLBuilder { + pub(crate) fn new(writer: W) -> Self { + let config = EmitterConfig { + write_document_declaration: false, + perform_escaping: false, + perform_indent: false, + line_separator: "".into(), + ..Default::default() + }; + let writer = config.create_writer(writer); XMLBuilder { writer } } - // Build types element - // i.e. - pub(crate) fn open_types(mut self, uri: &str) -> Self { - self.writer - .write(XmlEvent::start_element("Types").attr("xmlns", uri)) - .expect("should write to buf"); - self + #[inline] + pub(crate) fn write<'e>(mut self, event: impl Into>) -> Result { + self.writer.write(event)?; + Ok(self) } - // Build Override element - // i.e. - pub(crate) fn add_override(mut self, name: &str, content_type: &str) -> Self { - self.writer - .write( - XmlEvent::start_element("Override") - .attr("PartName", name) - .attr("ContentType", content_type), - ) - .expect("should write to buf"); - self.close() + #[inline(always)] + pub(crate) fn apply Result>(self, f: F) -> Result { + f(self) } - pub(crate) fn add_default(mut self, name: &str, extension: &str) -> Self { - self.writer - .write( - XmlEvent::start_element("Default") - .attr("ContentType", extension) - .attr("Extension", name), - ) - .expect("should write to buf"); - self.close() - } - - pub(crate) fn add_child(mut self, child: &T) -> Self - where - T: BuildXML, - { - let buf = child.build(); - let text = str::from_utf8(&buf).unwrap(); - self.writer.write(text).expect("should write to buf"); - self - } - - pub(crate) fn add_bytes(mut self, child: &[u8]) -> Self { - let text = str::from_utf8(child).unwrap(); - self.writer.write(text).expect("should write to buf"); - self - } - - pub(crate) fn add_optional_child(mut self, child: &Option) -> Self - where - T: BuildXML, - { - if let Some(c) = child { - self = self.add_child(c) + /// If `clause` argument is `true` or `Some(true)`, continue building XML. + /// + /// ```ignore + /// XMLBuilder::from(stream) + /// .apply_if(self.keep_lines, |b| b.keep_lines())? + /// ``` + #[inline(always)] + pub(crate) fn apply_if Result>( + self, + clause: impl Into>, + f: F, + ) -> Result { + if clause.into() == Some(true) { + f(self) + } else { + Ok(self) } - self } - pub(crate) fn add_children(mut self, children: &[T]) -> Self - where - T: BuildXML, - { - for c in children { - self = self.add_child(c); + /// If `opt` argument is `Some`, continue building XML. + /// + /// ```ignore + /// XMLBuilder::from(stream) + /// .apply_opt(self.config.language.as_ref(), |v, b| b.dc_language(v))? + /// ``` + #[inline(always)] + pub(crate) fn apply_opt Result>( + self, + opt: Option, + f: F, + ) -> Result { + if let Some(it) = opt { + f(it, self) + } else { + Ok(self) } - self } - // Close tag - pub(crate) fn close(mut self) -> Self { - self.writer - .write(XmlEvent::end_element()) - .expect("should end"); - self + #[inline(always)] + pub(crate) fn apply_each, F: Fn(T, Self) -> Result>( + mut self, + items: I, + f: F, + ) -> Result { + for item in items.into_iter() { + self = f(item, self)?; + } + Ok(self) } - // Write plain text - #[allow(dead_code)] - pub(crate) fn plain_text(mut self, t: &str) -> Self { - self.writer.write(t).unwrap(); - self + /// Pass the XML writer to the child, then get it back. + /// + /// Affects indentation as well as the stack of currently opened tags. + pub(crate) fn add_child(self, child: &impl BuildXML) -> Result { + Ok(child.build_to(self.writer)?.into()) } - pub(crate) fn build(self) -> Vec { - self.writer.into_inner() + pub(crate) fn add_optional_child(self, child: &Option) -> Result { + match child { + Some(ch) => self.add_child(ch), + None => Ok(self), + } + } + + pub(crate) fn add_children(mut self, children: &[impl BuildXML]) -> Result { + for ch in children { + self = self.add_child(ch)?; + } + Ok(self) + } + + /// Close the previously opened tag + pub(crate) fn close(self) -> Result { + self.write(XmlEvent::end_element()) + } + + /// Write a plain text. + /// + /// Finishes opened tags if there are any. + pub(crate) fn plain_text(self, t: &str) -> Result { + self.write(t) + } + + /// Prepare the internal raw stream for direct access. + /// + /// Finishes opened tags if there are any. + /// + /// ```ignore + /// let mut b = XMLBuilder::from(stream); + /// write!(b.inner_mut()?, "{}", self.0)?; + /// b.into_inner() + /// ``` + pub(crate) fn inner_mut(&mut self) -> Result<&mut W> { + self.writer.write("")?; // closes non-finished tags + Ok(self.writer.inner_mut()) + } + + /// Unwraps this `XmlBuilder`, returning the underlying writer. + /// + /// The return type is intentionally `Result`, to simplify chaining. + pub(crate) fn into_inner(self) -> Result> { + Ok(self.writer) + } +} + +// specific helpers, which probably should be somewhere else +impl XMLBuilder { + /// Build types element + /// + /// i.e. `` + pub(crate) fn open_types(self, uri: &str) -> Result { + self.write(XmlEvent::start_element("Types").attr("xmlns", uri)) + } + + /// Build Override element + /// + /// i.e. `` + pub(crate) fn add_override(self, name: &str, content_type: &str) -> Result { + self.write( + XmlEvent::start_element("Override") + .attr("PartName", name) + .attr("ContentType", content_type), + )? + .close() + } + + pub(crate) fn add_default(self, name: &str, extension: &str) -> Result { + self.write( + XmlEvent::start_element("Default") + .attr("ContentType", extension) + .attr("Extension", name), + )? + .close() } } @@ -136,16 +205,17 @@ mod tests { use super::*; #[test] - fn test_open_types() { - let b = XMLBuilder::new(); - let r = b - .open_types("http://example") - .plain_text("child") - .close() - .build(); + fn test_open_types() -> Result<()> { + let r = XMLBuilder::new(Vec::new()) + .open_types("http://example")? + .plain_text("child")? + .close()? + .into_inner()? + .into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#"child"# ); + Ok(()) } } diff --git a/docx-core/src/xml_builder/numbering.rs b/docx-core/src/xml_builder/numbering.rs index 1e0fef6..f1cb9e3 100644 --- a/docx-core/src/xml_builder/numbering.rs +++ b/docx-core/src/xml_builder/numbering.rs @@ -1,23 +1,23 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { - pub(crate) fn open_numbering(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:numbering") - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") - .attr("xmlns:v", "urn:schemas-microsoft-com:vml") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ), - ) - .expect("should write to buf"); - self +use std::io::Write; +use xml::writer::Result; + +impl XMLBuilder { + pub(crate) fn open_numbering(self) -> Result { + self.write( + XmlEvent::start_element("w:numbering") + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr("xmlns:o", "urn:schemas-microsoft-com:office:office") + .attr("xmlns:v", "urn:schemas-microsoft-com:vml") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ), + ) } } diff --git a/docx-core/src/xml_builder/pic.rs b/docx-core/src/xml_builder/pic.rs index 3e3fbb5..f6fd5ed 100644 --- a/docx-core/src/xml_builder/pic.rs +++ b/docx-core/src/xml_builder/pic.rs @@ -1,7 +1,9 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { +use std::io::Write; + +impl XMLBuilder { open!(open_pic, "pic:pic", "xmlns:pic"); open!(open_blip_fill, "pic:blipFill"); closed!(a_blip, "a:blip", "r:embed"); diff --git a/docx-core/src/xml_builder/properties.rs b/docx-core/src/xml_builder/properties.rs index 0e6a726..283743f 100644 --- a/docx-core/src/xml_builder/properties.rs +++ b/docx-core/src/xml_builder/properties.rs @@ -1,7 +1,9 @@ use super::XMLBuilder; use super::XmlEvent; -impl XMLBuilder { +use std::io::Write; + +impl XMLBuilder { // Build Properties element // i.e. open!(open_properties, "Properties", "xmlns", "xmlns:vt"); @@ -18,38 +20,42 @@ impl XMLBuilder { #[cfg(test)] mod tests { - - use super::XMLBuilder; + use super::*; use std::str; + use xml::writer::Result; #[test] - fn test_properties() { - let b = XMLBuilder::new(); + fn test_properties() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); let r = b - .open_properties("http://example", "http://example2") - .plain_text("child") - .close() - .build(); + .open_properties("http://example", "http://example2")? + .plain_text("child")? + .close()? + .into_inner()? + .into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#"child"# ); + Ok(()) } #[test] - fn test_template() { - let b = XMLBuilder::new(); - let r = b.template("0").build(); + fn test_template() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.template("0")?.into_inner()?.into_inner(); assert_eq!(str::from_utf8(&r).unwrap(), r#""#); + Ok(()) } #[test] - fn test_application() { - let b = XMLBuilder::new(); - let r = b.application("Lawgue").build(); + fn test_application() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.application("Lawgue")?.into_inner()?.into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#"Lawgue"# ); + Ok(()) } } diff --git a/docx-core/src/xml_builder/relationship.rs b/docx-core/src/xml_builder/relationship.rs index 10b0fdb..fc7319c 100644 --- a/docx-core/src/xml_builder/relationship.rs +++ b/docx-core/src/xml_builder/relationship.rs @@ -1,7 +1,8 @@ use super::XMLBuilder; use super::XmlEvent; +use std::io::Write; -impl XMLBuilder { +impl XMLBuilder { // Build RelationShips element // i.e. open!(open_relationships, "Relationships", "xmlns"); @@ -20,31 +21,37 @@ impl XMLBuilder { #[cfg(test)] mod tests { - - use super::XMLBuilder; + use super::*; use std::str; + use xml::writer::Result; #[test] - fn test_open_relationships() { - let b = XMLBuilder::new(); + fn test_open_relationships() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); let r = b - .open_relationships("http://example") - .plain_text("child") - .close() - .build(); + .open_relationships("http://example")? + .plain_text("child")? + .close()? + .into_inner()? + .into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#"child"# ); + Ok(()) } #[test] - fn test_relationship() { - let b = XMLBuilder::new(); - let r = b.relationship("rId1", "http://example", "core.xml").build(); + fn test_relationship() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b + .relationship("rId1", "http://example", "core.xml")? + .into_inner()? + .into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } } diff --git a/docx-core/src/xml_builder/settings.rs b/docx-core/src/xml_builder/settings.rs index 6009bb7..62ecfea 100644 --- a/docx-core/src/xml_builder/settings.rs +++ b/docx-core/src/xml_builder/settings.rs @@ -1,25 +1,24 @@ use super::XMLBuilder; use super::XmlEvent; +use std::io::Write; +use xml::writer::Result; -impl XMLBuilder { - pub(crate) fn open_settings(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:settings") - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr( - "xmlns:w15", - "http://schemas.microsoft.com/office/word/2012/wordml", - ), - ) - .expect("should write to buf"); - self +impl XMLBuilder { + pub(crate) fn open_settings(self) -> Result { + self.write( + XmlEvent::start_element("w:settings") + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr( + "xmlns:w15", + "http://schemas.microsoft.com/office/word/2012/wordml", + ), + ) } } diff --git a/docx-core/src/xml_builder/styles.rs b/docx-core/src/xml_builder/styles.rs index 99d219a..b94a445 100644 --- a/docx-core/src/xml_builder/styles.rs +++ b/docx-core/src/xml_builder/styles.rs @@ -1,37 +1,36 @@ use super::XMLBuilder; use super::XmlEvent; +use std::io::Write; +use xml::writer::Result; -impl XMLBuilder { +impl XMLBuilder { // Build w:style element // i.e. - pub(crate) fn open_styles(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("w:styles") - .attr( - "xmlns:mc", - "http://schemas.openxmlformats.org/markup-compatibility/2006", - ) - .attr( - "xmlns:r", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - ) - .attr( - "xmlns:w", - "http://schemas.openxmlformats.org/wordprocessingml/2006/main", - ) - .attr( - "xmlns:w14", - "http://schemas.microsoft.com/office/word/2010/wordml", - ) - .attr( - "xmlns:w15", - "http://schemas.microsoft.com/office/word/2012/wordml", - ) - .attr("mc:Ignorable", "w14 w15"), - ) - .expect("should write to buf"); - self + pub(crate) fn open_styles(self) -> Result { + self.write( + XmlEvent::start_element("w:styles") + .attr( + "xmlns:mc", + "http://schemas.openxmlformats.org/markup-compatibility/2006", + ) + .attr( + "xmlns:r", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + ) + .attr( + "xmlns:w", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + ) + .attr( + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + .attr( + "xmlns:w15", + "http://schemas.microsoft.com/office/word/2012/wordml", + ) + .attr("mc:Ignorable", "w14 w15"), + ) } } @@ -44,12 +43,13 @@ mod tests { use std::str; #[test] - fn test_declaration() { - let b = XMLBuilder::new(); - let r = b.open_styles().close().build(); + fn test_declaration() -> Result<()> { + let b = XMLBuilder::new(Vec::new()); + let r = b.open_styles()?.close()?.into_inner()?.into_inner(); assert_eq!( str::from_utf8(&r).unwrap(), r#""# ); + Ok(()) } } diff --git a/docx-core/src/xml_json/mod.rs b/docx-core/src/xml_json/mod.rs index 5e595e2..5a40f6b 100644 --- a/docx-core/src/xml_json/mod.rs +++ b/docx-core/src/xml_json/mod.rs @@ -8,7 +8,7 @@ // Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. // use serde::Serialize; use serde::Serialize; -use std::fmt; +use std::fmt::{Display, Formatter, Write}; use std::io::prelude::*; use std::io::Cursor; use std::str::FromStr; @@ -24,16 +24,12 @@ pub struct XmlDocument { pub data: Vec, } -// Print as JSON -impl fmt::Display for XmlDocument { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut s = String::new(); - - for d in self.data.iter() { - s = format!("{}{}", s, d); +impl Display for XmlDocument { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + for item in self.data.iter() { + item.fmt(f)?; } - - s.fmt(f) + Ok(()) } } @@ -59,57 +55,36 @@ pub struct XmlData { pub children: Vec, } -// Generate indentation -// fn indent(size: usize) -> String { -// const INDENT: &str = " "; -// (0..size) -// .map(|_| INDENT) -// .fold(String::with_capacity(size * INDENT.len()), |r, s| r + s) -// } +impl XmlData { + /// Format the XML data as a string + fn format(self: &XmlData, f: &mut Formatter, _depth: usize) -> std::fmt::Result { + write!(f, "<{}", self.name)?; -// Get the attributes as a string -fn attributes_to_string(attributes: &[(String, String)]) -> String { - attributes.iter().fold(String::new(), |acc, (k, v)| { - format!("{} {}=\"{}\"", acc, k, v) - }) -} - -// Format the XML data as a string -#[allow(clippy::only_used_in_recursion)] -fn format(data: &XmlData, depth: usize) -> String { - let sub = if data.children.is_empty() { - String::new() - } else { - let mut sub = "\n".to_string(); - for elmt in data.children.iter() { - sub = format!("{}{}", sub, format(elmt, depth + 1)); + for (key, val) in self.attributes.iter() { + write!(f, r#" {}="{}""#, key, val)?; } - sub - }; - let fmt_data = if let Some(ref d) = data.data { - format!("\n{}", d) - } else { - "".to_string() - }; + f.write_char('>')?; - format!( - "<{}{}>{}{}", - data.name, - attributes_to_string(&data.attributes), - fmt_data, - sub, - data.name - ) -} + if let Some(ref data) = self.data { + write!(f, "{}", data)? + } -impl fmt::Display for XmlData { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", format(self, 0)) + for child in self.children.iter() { + child.format(f, _depth + 1)?; + } + + write!(f, "", self.name) } } -// Get the XML atributes as a string +impl Display for XmlData { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + self.format(f, 0) + } +} + +/// Get the XML attributes as a string fn map_owned_attributes(attrs: Vec) -> Vec<(String, String)> { attrs .into_iter() @@ -128,7 +103,6 @@ fn map_owned_attributes(attrs: Vec) -> Vec<(Stri .collect() } -// Parse the data fn parse( mut data: Vec, current: Option, @@ -259,8 +233,8 @@ impl XmlDocument { #[derive(Debug, Clone, PartialEq)] pub struct ParseXmlError(String); -impl fmt::Display for ParseXmlError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Display for ParseXmlError { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { write!(f, "Coult not parse string to XML: {}", self.0) } } diff --git a/docx-wasm/test/__snapshots__/index.test.js.snap b/docx-wasm/test/__snapshots__/index.test.js.snap index 86edb8a..e02e17e 100644 --- a/docx-wasm/test/__snapshots__/index.test.js.snap +++ b/docx-wasm/test/__snapshots__/index.test.js.snap @@ -171033,1283 +171033,252 @@ Object { } `; -exports[`writer should write ToC with instrText 1`] = ` -" - - - - - -" -`; +exports[`writer should write ToC with instrText 1`] = `""`; -exports[`writer should write ToC with instrText 2`] = ` -" - - -Before contentsTOC \\\\uAfter contents - -Hello!! -World - -" -`; +exports[`writer should write ToC with instrText 2`] = `"Before contentsTOC \\\\uAfter contentsHello!!World"`; -exports[`writer should write ToC with items 1`] = ` -" - - - - - -" -`; +exports[`writer should write ToC with items 1`] = `""`; -exports[`writer should write ToC with items 2`] = ` -" - - - - - - - -TOCHello!!PAGEREF _Toc00000000 \\\\h2 - - -WorldPAGEREF _Toc00000001 \\\\h3 - - -Hello!! -World - -" -`; +exports[`writer should write ToC with items 2`] = `"TOCHello!!PAGEREF _Toc00000000 \\\\h2WorldPAGEREF _Toc00000001 \\\\h3Hello!!World"`; -exports[`writer should write align 1`] = ` -" - - - - - -" -`; +exports[`writer should write align 1`] = `""`; -exports[`writer should write align 2`] = ` -" - - Hello world!! - -" -`; +exports[`writer should write align 2`] = `"Hello world!!"`; -exports[`writer should write anchor hyperlink 1`] = ` -" - - - - - -" -`; +exports[`writer should write anchor hyperlink 1`] = `""`; -exports[`writer should write anchor hyperlink 2`] = ` -" - - Hello!! -World!! - -" -`; +exports[`writer should write anchor hyperlink 2`] = `"Hello!!World!!"`; -exports[`writer should write auto items ToC 1`] = ` -" - - - - - -" -`; +exports[`writer should write auto items ToC 1`] = `""`; -exports[`writer should write auto items ToC 2`] = ` -" - - - - - - - -TOCHello!!PAGEREF _Toc00000000 \\\\h1 - - -WorldPAGEREF _Toc00000001 \\\\h1 - - -Hello!! -World - -" -`; +exports[`writer should write auto items ToC 2`] = `"TOCHello!!PAGEREF _Toc00000000 \\\\h1WorldPAGEREF _Toc00000001 \\\\h1Hello!!World"`; -exports[`writer should write cell shading 1`] = ` -" - - - - - -" -`; +exports[`writer should write cell shading 1`] = `""`; -exports[`writer should write cell shading 2`] = ` -" - - - - - - -Hello!! - -" -`; +exports[`writer should write cell shading 2`] = `"Hello!!"`; -exports[`writer should write cell shading 3`] = ` -" - - -" -`; +exports[`writer should write cell shading 3`] = `""`; -exports[`writer should write custom props 1`] = ` -" - - - {\\"world\\": 0} - -" -`; +exports[`writer should write custom props 1`] = `"{\\"world\\": 0}"`; -exports[`writer should write custom props 2`] = ` -" - - - - - -" -`; +exports[`writer should write custom props 2`] = `""`; -exports[`writer should write custom props 3`] = ` -" - - Hello!! - -" -`; +exports[`writer should write custom props 3`] = `"Hello!!"`; -exports[`writer should write custom props 4`] = ` -" - - -" -`; +exports[`writer should write custom props 4`] = `""`; exports[`writer should write customItem 1`] = `""`; exports[`writer should write customItem 2`] = `""`; -exports[`writer should write customItem 3`] = ` -" - - - - - -" -`; +exports[`writer should write customItem 3`] = `""`; -exports[`writer should write customItem 4`] = ` -" - - - - - - -" -`; +exports[`writer should write customItem 4`] = `""`; exports[`writer should write customItem 5`] = `""`; -exports[`writer should write customItem 6`] = ` -" - - -" -`; - -exports[`writer should write customItem 7`] = ` -" -" -`; - -exports[`writer should write default font 1`] = ` -" - - - - - -" -`; - -exports[`writer should write default font 2`] = ` -" - - Hello world!!!! - -" -`; - -exports[`writer should write default font 3`] = ` -" - - -" -`; - -exports[`writer should write default line spacing 1`] = ` -" - - - - - -" -`; - -exports[`writer should write default line spacing 2`] = ` -" - - Hello - -" -`; - -exports[`writer should write default line spacing 3`] = ` -" - - -" -`; - -exports[`writer should write deleted ToC 1`] = ` -" - - - - - -" -`; - -exports[`writer should write deleted ToC 2`] = ` -" - - -TOC \\\\uAfter contents - -Hello!! -World - -" -`; - -exports[`writer should write dirty and disable auto items ToC 1`] = ` -" - - - - - -" -`; - -exports[`writer should write dirty and disable auto items ToC 2`] = ` -" - - -TOC - -Hello!! -World - -" -`; - -exports[`writer should write doc grid 1`] = ` -" - - - - - -" -`; - -exports[`writer should write doc grid 2`] = ` -" - - Hello world!!!! -" -`; - -exports[`writer should write doc grid 3`] = ` -" - - -" -`; - -exports[`writer should write doc vars 1`] = ` -" - - - - - -" -`; - -exports[`writer should write doc vars 2`] = ` -" - - Hello world!!!! - -" -`; - -exports[`writer should write doc vars 3`] = ` -" - - -" -`; - -exports[`writer should write evenFooter with table for default section 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write evenFooter with table for default section 2`] = ` -" - - -" -`; - -exports[`writer should write evenFooter with table for default section 3`] = ` -" - - - - - -Hello Footer!!" -`; - -exports[`writer should write evenFooter with table for default section 4`] = ` -" -" -`; - -exports[`writer should write external hyperlink 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write external hyperlink 2`] = ` -" - - Hello!! - -" -`; - -exports[`writer should write firstHeader with table for default section 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write firstHeader with table for default section 2`] = ` -" - - - -" -`; - -exports[`writer should write firstHeader with table for default section 3`] = ` -" - - - - - -Hello Header!!" -`; - -exports[`writer should write firstHeader with table for default section 4`] = ` -" -" -`; - -exports[`writer should write footer for default section 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write footer for default section 2`] = ` -" - - World -" -`; - -exports[`writer should write footer for default section 3`] = ` -" -Hello Footer" -`; - -exports[`writer should write footer for default section 4`] = ` -" -" -`; - -exports[`writer should write header for default section 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write header for default section 2`] = ` -" - - World -" -`; - -exports[`writer should write hello 1`] = ` -" - - - - - -" -`; - -exports[`writer should write hello 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write hello 3`] = ` -" - - -" -`; - -exports[`writer should write image in header 1`] = ` -" - - - - - - - -" -`; - -exports[`writer should write image in header 2`] = ` -" - - Hello world!! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`writer should write inline image 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write inline image 2`] = ` -" - - Hello world!! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`writer should write inline jpeg image 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write inline jpeg image 2`] = ` -" - - Hello world!! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`writer should write jpeg image with del 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write jpeg image with del 2`] = ` -" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`writer should write jpeg image with ins 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write jpeg image with ins 2`] = ` -" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`writer should write line spacing 1`] = ` -" - - - - - -" -`; - -exports[`writer should write line spacing 2`] = ` -" - - Hello - -" -`; - -exports[`writer should write line spacing 3`] = ` -" - - -" -`; - -exports[`writer should write lvlOverride with level 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write lvlOverride with level 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write lvlOverride with level 3`] = ` -" - - - - " -`; - -exports[`writer should write nested table 1`] = ` -" - - - - - -" -`; - -exports[`writer should write nested table 2`] = ` -" - - - - - - - - - - - -Hello world!! - -" -`; - -exports[`writer should write nested table 3`] = ` -" - - -" -`; - -exports[`writer should write pPrChange with deleted numbering 1`] = ` -" - - - - - -" -`; - -exports[`writer should write pPrChange with deleted numbering 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write pPrChange with deleted numbering 3`] = ` -" - - - - -" -`; - -exports[`writer should write pPrChange with inserted numbering 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write pPrChange with inserted numbering 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write pPrChange with inserted numbering 3`] = ` -" - - - - -" -`; - -exports[`writer should write page margin 1`] = ` -" - - - - - -" -`; - -exports[`writer should write page margin 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write page margin 3`] = ` -" - - -" -`; - -exports[`writer should write page orientation 1`] = ` -" - - - - - -" -`; - -exports[`writer should write page orientation 2`] = ` -" - - Hello - -" -`; - -exports[`writer should write page orientation 3`] = ` -" - - -" -`; - -exports[`writer should write page size 1`] = ` -" - - - - - -" -`; - -exports[`writer should write page size 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write page size 3`] = ` -" - - -" -`; - -exports[`writer should write pageNum in header 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write pageNum in header 2`] = ` -" - - Hello world!! PAGE1 / NUMPAGES1 -" -`; - -exports[`writer should write pageNum in header 3`] = ` -" -Hello world!! PAGE1 / NUMPAGES1" -`; - -exports[`writer should write pageNum in header 4`] = ` -" -" -`; - -exports[`writer should write paragraph delete 1`] = ` -" - - - - - - -" -`; - -exports[`writer should write paragraph delete 2`] = ` -" - - Hello world!!Foo - -" -`; - -exports[`writer should write paragraph delete 3`] = ` -" - - - - -" -`; - -exports[`writer should write ptab 1`] = ` -" - - - - - -" -`; - -exports[`writer should write ptab 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write ptab 3`] = ` -" - - -" -`; - -exports[`writer should write strike 1`] = ` -" - - - - - -" -`; - -exports[`writer should write strike 2`] = ` -" - - Hello world!! - -" -`; - -exports[`writer should write strike 3`] = ` -" - - -" -`; - -exports[`writer should write style 1`] = ` -" - - - - - -" -`; - -exports[`writer should write style 2`] = ` -" - - Hello - - - - -Hello - -" -`; - -exports[`writer should write style 3`] = ` -" - - - - -" -`; - -exports[`writer should write table layout 1`] = ` -" - - - - - -" -`; - -exports[`writer should write table layout 2`] = ` -" - - - - - - -Hello!! - -" -`; - -exports[`writer should write table layout 3`] = ` -" - - -" -`; - -exports[`writer should write text border 1`] = ` -" - - - - - -" -`; - -exports[`writer should write text border 2`] = ` -" - - Hello World! - -" -`; - -exports[`writer should write text border 3`] = ` -" - - -" -`; - -exports[`writer should write tl2br and tr2bl cells 1`] = ` -" - - - - - -" -`; - -exports[`writer should write tl2br and tr2bl cells 2`] = ` -" - - - - - - -Hello!!Hello!!Hello!! - -" -`; - -exports[`writer should write tl2br and tr2bl cells 3`] = ` -" - - -" -`; +exports[`writer should write customItem 6`] = `""`; + +exports[`writer should write customItem 7`] = `""`; + +exports[`writer should write default font 1`] = `""`; + +exports[`writer should write default font 2`] = `"Hello world!!!!"`; + +exports[`writer should write default font 3`] = `""`; + +exports[`writer should write default line spacing 1`] = `""`; + +exports[`writer should write default line spacing 2`] = `"Hello "`; + +exports[`writer should write default line spacing 3`] = `""`; + +exports[`writer should write deleted ToC 1`] = `""`; + +exports[`writer should write deleted ToC 2`] = `"TOC \\\\uAfter contentsHello!!World"`; + +exports[`writer should write dirty and disable auto items ToC 1`] = `""`; + +exports[`writer should write dirty and disable auto items ToC 2`] = `"TOCHello!!World"`; + +exports[`writer should write doc grid 1`] = `""`; + +exports[`writer should write doc grid 2`] = `"Hello world!!!!"`; + +exports[`writer should write doc grid 3`] = `""`; + +exports[`writer should write doc vars 1`] = `""`; + +exports[`writer should write doc vars 2`] = `"Hello world!!!!"`; + +exports[`writer should write doc vars 3`] = `""`; + +exports[`writer should write evenFooter with table for default section 1`] = `""`; + +exports[`writer should write evenFooter with table for default section 2`] = `""`; + +exports[`writer should write evenFooter with table for default section 3`] = `"Hello Footer!!"`; + +exports[`writer should write evenFooter with table for default section 4`] = `""`; + +exports[`writer should write external hyperlink 1`] = `""`; + +exports[`writer should write external hyperlink 2`] = `"Hello!!"`; + +exports[`writer should write firstHeader with table for default section 1`] = `""`; + +exports[`writer should write firstHeader with table for default section 2`] = `""`; + +exports[`writer should write firstHeader with table for default section 3`] = `"Hello Header!!"`; + +exports[`writer should write firstHeader with table for default section 4`] = `""`; + +exports[`writer should write footer for default section 1`] = `""`; + +exports[`writer should write footer for default section 2`] = `"World "`; + +exports[`writer should write footer for default section 3`] = `"Hello Footer"`; + +exports[`writer should write footer for default section 4`] = `""`; + +exports[`writer should write header for default section 1`] = `""`; + +exports[`writer should write header for default section 2`] = `"World "`; + +exports[`writer should write hello 1`] = `""`; + +exports[`writer should write hello 2`] = `"Hello world!!"`; + +exports[`writer should write hello 3`] = `""`; + +exports[`writer should write image in header 1`] = `""`; + +exports[`writer should write image in header 2`] = `"Hello world!!"`; + +exports[`writer should write inline image 1`] = `""`; + +exports[`writer should write inline image 2`] = `"Hello world!!"`; + +exports[`writer should write inline jpeg image 1`] = `""`; + +exports[`writer should write inline jpeg image 2`] = `"Hello world!!"`; + +exports[`writer should write jpeg image with del 1`] = `""`; + +exports[`writer should write jpeg image with del 2`] = `""`; + +exports[`writer should write jpeg image with ins 1`] = `""`; + +exports[`writer should write jpeg image with ins 2`] = `""`; + +exports[`writer should write line spacing 1`] = `""`; + +exports[`writer should write line spacing 2`] = `"Hello "`; + +exports[`writer should write line spacing 3`] = `""`; + +exports[`writer should write lvlOverride with level 1`] = `""`; + +exports[`writer should write lvlOverride with level 2`] = `"Hello world!!"`; + +exports[`writer should write lvlOverride with level 3`] = `""`; + +exports[`writer should write nested table 1`] = `""`; + +exports[`writer should write nested table 2`] = `"Hello world!!"`; + +exports[`writer should write nested table 3`] = `""`; + +exports[`writer should write pPrChange with deleted numbering 1`] = `""`; + +exports[`writer should write pPrChange with deleted numbering 2`] = `"Hello world!!"`; + +exports[`writer should write pPrChange with deleted numbering 3`] = `""`; + +exports[`writer should write pPrChange with inserted numbering 1`] = `""`; + +exports[`writer should write pPrChange with inserted numbering 2`] = `"Hello world!!"`; + +exports[`writer should write pPrChange with inserted numbering 3`] = `""`; + +exports[`writer should write page margin 1`] = `""`; + +exports[`writer should write page margin 2`] = `"Hello world!!"`; + +exports[`writer should write page margin 3`] = `""`; + +exports[`writer should write page orientation 1`] = `""`; + +exports[`writer should write page orientation 2`] = `"Hello "`; + +exports[`writer should write page orientation 3`] = `""`; + +exports[`writer should write page size 1`] = `""`; + +exports[`writer should write page size 2`] = `"Hello world!!"`; + +exports[`writer should write page size 3`] = `""`; + +exports[`writer should write pageNum in header 1`] = `""`; + +exports[`writer should write pageNum in header 2`] = `"Hello world!! PAGE1 / NUMPAGES1"`; + +exports[`writer should write pageNum in header 3`] = `"Hello world!! PAGE1 / NUMPAGES1"`; + +exports[`writer should write pageNum in header 4`] = `""`; + +exports[`writer should write paragraph delete 1`] = `""`; + +exports[`writer should write paragraph delete 2`] = `"Hello world!!Foo"`; + +exports[`writer should write paragraph delete 3`] = `""`; + +exports[`writer should write ptab 1`] = `""`; + +exports[`writer should write ptab 2`] = `"Hello world!!"`; + +exports[`writer should write ptab 3`] = `""`; + +exports[`writer should write strike 1`] = `""`; + +exports[`writer should write strike 2`] = `"Hello world!!"`; + +exports[`writer should write strike 3`] = `""`; + +exports[`writer should write style 1`] = `""`; + +exports[`writer should write style 2`] = `"HelloHello"`; + +exports[`writer should write style 3`] = `""`; + +exports[`writer should write table layout 1`] = `""`; + +exports[`writer should write table layout 2`] = `"Hello!!"`; + +exports[`writer should write table layout 3`] = `""`; + +exports[`writer should write text border 1`] = `""`; + +exports[`writer should write text border 2`] = `"Hello World!"`; + +exports[`writer should write text border 3`] = `""`; + +exports[`writer should write tl2br and tr2bl cells 1`] = `""`; + +exports[`writer should write tl2br and tr2bl cells 2`] = `"Hello!!Hello!!Hello!!"`; + +exports[`writer should write tl2br and tr2bl cells 3`] = `""`; exports[`writer should write webextension 1`] = `""`; exports[`writer should write webextension 2`] = `""`; -exports[`writer should write webextension 3`] = ` -" - - - - - - -" -`; +exports[`writer should write webextension 3`] = `""`; -exports[`writer should write webextension 4`] = ` -" - - - - - -" -`; +exports[`writer should write webextension 4`] = `""`; exports[`writer should write webextension 5`] = `""`; -exports[`writer should write webextension 6`] = ` -" - - -" -`; +exports[`writer should write webextension 6`] = `""`; -exports[`writer should write webextension 7`] = ` -" - - - - - - - - -" -`; +exports[`writer should write webextension 7`] = `""`; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..b6f799d --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +tab_spaces = 4