Implement streaming writers (#765)

* Make XMLBuilder generic

* Reduce allocations at XmlData display impl

* Implement streaming writers

- Extend BuildXML trait, add the streaming method
- Remove impls for Box<Ty>, as they can be implemented on the trait level
- Rewrite build() methods in chaining style, backed by apply_* helpers
- Remove quite a few allocations, though numbers still produce them
- Add spaces between children nodes, fix tests

* Add rustfmt.toml and format code

* Fix clippy warnings

* Expose the BuildXML trait without displaying its methods in hints
main
Igor Strebz 2024-11-05 05:22:32 +03:00 committed by GitHub
parent 72637a4dc0
commit 238d2bc3fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
186 changed files with 3595 additions and 4500 deletions

View File

@ -1,3 +1,38 @@
use crate::xml_builder::XMLBuilder;
use std::io::Write;
pub trait BuildXML {
fn build(&self) -> Vec<u8>;
/// Write XML to the output stream.
#[doc(hidden)]
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>>;
#[doc(hidden)]
fn build(&self) -> Vec<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
(*self).build_to(stream)
}
}
impl<T: BuildXML> BuildXML for Box<T> {
/// Building XML from `Box<T>` is the same as from `T`.
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
(**self).build_to(stream)
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:comments xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14 wp14" />"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:comments xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14 wp14" />"#
);
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_comments_extended()?
.add_children(&self.children)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"></Override></Types>"#;
let xml = r#"<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"></Override></Types>"#;
let c = ContentTypes::from_xml(xml.as_bytes()).unwrap();
let mut types = BTreeMap::new();
types.insert(

View File

@ -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<u8> {
self.0.to_string().as_bytes().to_vec()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<ds:datastoreItem ds:itemID="{06AC5857-5C65-A94A-BCEC-37356A209BC3}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml">
<ds:schemaRefs>
<ds:schemaRef ds:uri="https://hoge.com"></ds:schemaRef></ds:schemaRefs></ds:datastoreItem>"#,
r#"<ds:datastoreItem ds:itemID="{06AC5857-5C65-A94A-BCEC-37356A209BC3}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml"><ds:schemaRefs><ds:schemaRef ds:uri="https://hoge.com"></ds:schemaRef></ds:schemaRefs></ds:datastoreItem>"#,
)
.unwrap();
assert_eq!(
c.0.to_string(),
r#"<ds:datastoreItem ds:itemID="{06AC5857-5C65-A94A-BCEC-37356A209BC3}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml">
<ds:schemaRefs>
<ds:schemaRef ds:uri="https://hoge.com"></ds:schemaRef></ds:schemaRefs></ds:datastoreItem>"#
r#"<ds:datastoreItem ds:itemID="{06AC5857-5C65-A94A-BCEC-37356A209BC3}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml"><ds:schemaRefs><ds:schemaRef ds:uri="https://hoge.com"></ds:schemaRef></ds:schemaRefs></ds:datastoreItem>"#
);
assert_eq!(
serde_json::to_string(&c).unwrap(),

View File

@ -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<u8> {
let mut b = XMLBuilder::new();
b = b.declaration(Some(false));
b = b
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" />"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" />"#
);
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dcterms:created xsi:type="dcterms:W3CDTF">1970-01-01T00:00:00Z</dcterms:created>
<dc:creator>unknown</dc:creator>
<cp:lastModifiedBy>unknown</cp:lastModifiedBy>
<dcterms:modified xsi:type="dcterms:W3CDTF">1970-01-01T00:00:00Z</dcterms:modified>
<cp:revision>1</cp:revision>
</cp:coreProperties>"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">1970-01-01T00:00:00Z</dcterms:created><dc:creator>unknown</dc:creator><cp:lastModifiedBy>unknown</cp:lastModifiedBy><dcterms:modified xsi:type="dcterms:W3CDTF">1970-01-01T00:00:00Z</dcterms:modified><cp:revision>1</cp:revision></cp:coreProperties>"#
);
}
@ -162,18 +140,7 @@ mod tests {
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dcterms:created xsi:type="dcterms:W3CDTF">2019-01-01</dcterms:created>
<dc:creator>foo</dc:creator>
<cp:lastModifiedBy>go</cp:lastModifiedBy>
<dcterms:modified xsi:type="dcterms:W3CDTF">2019-01-01</dcterms:modified>
<cp:revision>1</cp:revision>
<dc:description>bar</dc:description>
<dc:language>en</dc:language>
<dc:subject>subject</dc:subject>
<dc:title>title</dc:title>
</cp:coreProperties>"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">2019-01-01</dcterms:created><dc:creator>foo</dc:creator><cp:lastModifiedBy>go</cp:lastModifiedBy><dcterms:modified xsi:type="dcterms:W3CDTF">2019-01-01</dcterms:modified><cp:revision>1</cp:revision><dc:description>bar</dc:description><dc:language>en</dc:language><dc:subject>subject</dc:subject><dc:title>title</dc:title></cp:coreProperties>"#
);
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<u8> {
XMLBuilder::new()
.declaration(Some(true))
.open_document()
.open_body()
.add_children(&self.children)
.add_child(&self.section_property)
.close()
.close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14">
<w:body><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" />
</w:sectPr></w:body>
</w:document>"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14"><w:body><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /></w:sectPr></w:body></w:document>"#
);
}
@ -294,12 +297,7 @@ mod tests {
let b = Document::new().add_table_of_contents(toc).build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14">
<w:body><w:sdt><w:sdtPr><w:rPr /></w:sdtPr><w:sdtContent><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType="begin" w:dirty="true" /><w:instrText>TOC \o &quot;1-3&quot;</w:instrText><w:fldChar w:fldCharType="separate" w:dirty="false" /></w:r></w:p><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType="end" w:dirty="false" /></w:r></w:p></w:sdtContent>
</w:sdt><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" />
</w:sectPr></w:body>
</w:document>"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14"><w:body><w:sdt><w:sdtPr><w:rPr /></w:sdtPr><w:sdtContent><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType="begin" w:dirty="true" /><w:instrText>TOC \o &quot;1-3&quot;</w:instrText><w:fldChar w:fldCharType="separate" w:dirty="false" /></w:r></w:p><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType="end" w:dirty="false" /></w:r></w:p></w:sdtContent></w:sdt><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /></w:sectPr></w:body></w:document>"#
);
}
@ -311,11 +309,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14">
<w:body><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="2" />
</w:sectPr></w:body>
</w:document>"#
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14"><w:body><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="2" /></w:sectPr></w:body></w:document>"#
);
}
}

View File

@ -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<u8> {
let mut b = XMLBuilder::new();
b = b
.declaration(None)
.open_relationships("http://schemas.openxmlformats.org/package/2006/relationships")
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_graphic("http://schemas.openxmlformats.org/drawingml/2006/main")?
.add_children(&self.children)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_abstract_num(&self.id.to_string())?
.add_children(&self.levels)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.adjust_right_ind(self.0).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.adjust_right_ind(self.0)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.based_on(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).based_on(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.b().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).b()?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.b_cs().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).b_cs()?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.bookmark_end(&format!("{}", self.id)).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.bookmark_end(&self.id.to_string())?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.bookmark_start(&format!("{}", self.id), &self.name)
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.bookmark_start(&self.id.to_string(), &self.name)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.br(&self.break_type.to_string()).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.br(&self.break_type.to_string())?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.cant_split().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).cant_split()?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.caps(&self.val.to_string()).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.caps(&self.val.to_string())?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:tcMar>
<w:top w:w="10" w:type="dxa" />
</w:tcMar>"#
r#"<w:tcMar><w:top w:w="10" w:type="dxa" /></w:tcMar>"#
);
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.spacing(self.value).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).spacing(self.value)?.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new().color(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).color(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<u8> {
XMLBuilder::new()
.open_comment(&format!("{}", self.id), &self.author, &self.date, "")
.add_children(&self.children)
.close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_comment(&self.id.to_string(), &self.author, &self.date, "")?
.add_children(&self.children)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new()
.comment_extended(&self.paragraph_id, self.done, &self.parent_paragraph_id)
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.comment_extended(&self.paragraph_id, self.done, &self.parent_paragraph_id)?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:r>
<w:rPr />
</w:r>
<w:commentRangeEnd w:id="1" />
<w:r>
<w:commentReference w:id="1" />
</w:r>"#
r#"<w:r><w:rPr /></w:r><w:commentRangeEnd w:id="1" /><w:r><w:commentReference w:id="1" /></w:r>"#
);
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.comment_range_start(&format!("{}", self.id)).build()
}
}
impl BuildXML for Box<CommentRangeStart> {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
b.comment_range_start(&format!("{}", self.id)).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.comment_range_start(&self.id.to_string())?
.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.data_binding(
self.xpath.as_ref(),
self.prefix_mappings.as_ref(),
self.store_item_id.as_ref(),
)
.build()
)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.default_tab_stop(self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.default_tab_stop(self.val)?
.into_inner()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
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<DeleteInstrText> {
fn build(&self) -> Vec<u8> {
self.as_ref().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
XMLBuilder::new().delete_text(&self.text, true).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.delete_text(&self.text, true)?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_doc_defaults()?
.add_child(&self.run_property_default)?
.add_child(&self.paragraph_property_default)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.doc_grid(&self.grid_type, self.line_pitch, self.char_space)
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.doc_grid(&self.grid_type, self.line_pitch, self.char_space)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
let id = format!("{{{}}}", self.id);
b.doc_id(&id).build()
XMLBuilder::from(stream).doc_id(&id)?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.doc_var(&self.name, &self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.doc_var(&self.name, &self.val)?
.into_inner()
}
}

View File

@ -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<Drawing> {
fn build(&self) -> Vec<u8> {
self.as_ref().build()
}
}
impl BuildXML for Drawing {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
let mut b = b.open_drawing();
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="3048000" cy="2286000" />
<wp:effectExtent b="0" l="0" r="0" t="0" />
<wp:docPr id="1" name="Figure" />
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="" />
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rIdImage123" />
<a:srcRect />
<a:stretch>
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm rot="0">
<a:off x="0" y="0" />
<a:ext cx="3048000" cy="2286000" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic></a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>"#
r#"<w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="3048000" cy="2286000" /><wp:effectExtent b="0" l="0" r="0" t="0" /><wp:docPr id="1" name="Figure" /><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" /></wp:cNvGraphicFramePr><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="" /><pic:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1" /></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImage123" /><a:srcRect /><a:stretch><a:fillRect /></a:stretch></pic:blipFill><pic:spPr bwMode="auto"><a:xfrm rot="0"><a:off x="0" y="0" /><a:ext cx="3048000" cy="2286000" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing>"#
);
}
@ -212,43 +177,7 @@ mod tests {
let d = Drawing::new().pic(pic).build();
assert_eq!(
str::from_utf8(&d).unwrap(),
r#"<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="3048000" cy="2286000" />
<wp:effectExtent b="0" l="0" r="0" t="0" />
<wp:wrapNone />
<wp:docPr id="1" name="Figure" />
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="" />
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rIdImage123" />
<a:srcRect />
<a:stretch>
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm rot="0">
<a:off x="0" y="0" />
<a:ext cx="3048000" cy="2286000" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic></a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>"#
r#"<w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="3048000" cy="2286000" /><wp:effectExtent b="0" l="0" r="0" t="0" /><wp:wrapNone /><wp:docPr id="1" name="Figure" /><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" /></wp:cNvGraphicFramePr><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="" /><pic:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1" /></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImage123" /><a:srcRect /><a:stretch><a:fillRect /></a:stretch></pic:blipFill><pic:spPr bwMode="auto"><a:xfrm rot="0"><a:off x="0" y="0" /><a:ext cx="3048000" cy="2286000" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing>"#
);
}
@ -261,50 +190,7 @@ mod tests {
let d = Drawing::new().pic(pic).build();
assert_eq!(
str::from_utf8(&d).unwrap(),
r#"<w:drawing>
<wp:anchor distT="0" distB="0" distL="0" distR="0" simplePos="0" allowOverlap="0" behindDoc="0" locked="0" layoutInCell="0" relativeHeight="190500">
<wp:simplePos x="0" y="0" />
<wp:positionH relativeFrom="column">
<wp:align>right</wp:align>
</wp:positionH>
<wp:positionV relativeFrom="paragraph">
<wp:posOffset>0</wp:posOffset>
</wp:positionV>
<wp:extent cx="3048000" cy="2286000" />
<wp:effectExtent b="0" l="0" r="0" t="0" />
<wp:wrapSquare wrapText="bothSides" />
<wp:docPr id="1" name="Figure" />
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="" />
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rIdImage123" />
<a:srcRect />
<a:stretch>
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm rot="0">
<a:off x="0" y="0" />
<a:ext cx="3048000" cy="2286000" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic></a:graphicData>
</a:graphic>
</wp:anchor>
</w:drawing>"#
r#"<w:drawing><wp:anchor distT="0" distB="0" distL="0" distR="0" simplePos="0" allowOverlap="0" behindDoc="0" locked="0" layoutInCell="0" relativeHeight="190500"><wp:simplePos x="0" y="0" /><wp:positionH relativeFrom="column"><wp:align>right</wp:align></wp:positionH><wp:positionV relativeFrom="paragraph"><wp:posOffset>0</wp:posOffset></wp:positionV><wp:extent cx="3048000" cy="2286000" /><wp:effectExtent b="0" l="0" r="0" t="0" /><wp:wrapSquare wrapText="bothSides" /><wp:docPr id="1" name="Figure" /><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" /></wp:cNvGraphicFramePr><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="" /><pic:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1" /></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImage123" /><a:srcRect /><a:stretch><a:fillRect /></a:stretch></pic:blipFill><pic:spPr bwMode="auto"><a:xfrm rot="0"><a:off x="0" y="0" /><a:ext cx="3048000" cy="2286000" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:anchor></w:drawing>"#
);
}
@ -319,50 +205,7 @@ mod tests {
let d = Drawing::new().pic(pic).build();
assert_eq!(
str::from_utf8(&d).unwrap(),
r#"<w:drawing>
<wp:anchor distT="0" distB="0" distL="0" distR="0" simplePos="0" allowOverlap="0" behindDoc="0" locked="0" layoutInCell="0" relativeHeight="190500">
<wp:simplePos x="0" y="0" />
<wp:positionH relativeFrom="margin">
<wp:posOffset>2857500</wp:posOffset>
</wp:positionH>
<wp:positionV relativeFrom="margin">
<wp:posOffset>3810000</wp:posOffset>
</wp:positionV>
<wp:extent cx="3048000" cy="2286000" />
<wp:effectExtent b="0" l="0" r="0" t="0" />
<wp:wrapSquare wrapText="bothSides" />
<wp:docPr id="1" name="Figure" />
<wp:cNvGraphicFramePr>
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" />
</wp:cNvGraphicFramePr>
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="" />
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rIdImage123" />
<a:srcRect />
<a:stretch>
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm rot="0">
<a:off x="0" y="0" />
<a:ext cx="3048000" cy="2286000" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic></a:graphicData>
</a:graphic>
</wp:anchor>
</w:drawing>"#
r#"<w:drawing><wp:anchor distT="0" distB="0" distL="0" distR="0" simplePos="0" allowOverlap="0" behindDoc="0" locked="0" layoutInCell="0" relativeHeight="190500"><wp:simplePos x="0" y="0" /><wp:positionH relativeFrom="margin"><wp:posOffset>2857500</wp:posOffset></wp:positionH><wp:positionV relativeFrom="margin"><wp:posOffset>3810000</wp:posOffset></wp:positionV><wp:extent cx="3048000" cy="2286000" /><wp:effectExtent b="0" l="0" r="0" t="0" /><wp:wrapSquare wrapText="bothSides" /><wp:docPr id="1" name="Figure" /><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" /></wp:cNvGraphicFramePr><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="" /><pic:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1" /></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImage123" /><a:srcRect /><a:stretch><a:fillRect /></a:stretch></pic:blipFill><pic:spPr bwMode="auto"><a:xfrm rot="0"><a:off x="0" y="0" /><a:ext cx="3048000" cy="2286000" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:anchor></w:drawing>"#
);
}
}

View File

@ -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<u8> {
XMLBuilder::new()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.field_character(
&format!("{}", self.field_char_type),
&format!("{}", &self.dirty),
)
.build()
)?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:font w:name="Arial">
<w:charset w:val="00" />
<w:family w:val="swiss" />
<w:pitch w:val="variable" />
</w:font>"#
r#"<w:font w:name="Arial"><w:charset w:val="00" /><w:family w:val="swiss" /><w:pitch w:val="variable" /></w:font>"#
);
}
}

View File

@ -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<u8> {
XMLBuilder::new()
.footer_reference(&self.footer_type, &self.id)
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.footer_reference(&self.footer_type, &self.id)?
.into_inner()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
// 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()
}
}

View File

@ -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<Footnote> for FootnoteReference {
}
impl BuildXML for FootnoteReference {
fn build(&self) -> Vec<u8> {
XMLBuilder::new().footnote_reference(self.id).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.footnote_reference(self.id)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.frame_property(self).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).frame_property(self)?.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new().grid_span(self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).grid_span(self.val)?.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new()
.header_reference(&self.header_type, &self.id)
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.header_reference(&self.header_type, &self.id)?
.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new().highlight(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).highlight(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
let mut b = XMLBuilder::new();
match self.link {
HyperlinkData::Anchor { ref anchor } => {
b = b.open_hyperlink(
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
XMLBuilder::new()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.indent(
self.start,
self.special_indent,
self.end.unwrap_or_default(),
self.start_chars,
)
.build()
)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.indent_level(self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.indent_level(self.val)?
.into_inner()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<u8> {
XMLBuilder::new()
.open_insert(&self.generate(), &self.author, &self.date)
.add_children(&self.children)
.close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_insert(&self.generate(), &self.author, &self.date)?
.add_children(&self.children)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
let instr = "NUMPAGES".to_owned();
instr.into()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.plain_text("NUMPAGES")?
.into_inner()
}
}

View File

@ -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<u8> {
let instr = "PAGE".to_owned();
instr.into()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).plain_text("PAGE")?.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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"#);
}
}

View File

@ -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<u8> {
let mut instr = format!("TC {}", self.text);
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<InstrText> {
fn build(&self) -> Vec<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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 {

View File

@ -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<u8> {
let mut instr = "TOC".to_string();
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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 &quot;{}&quot;", instr, t);
write!(raw, " \\a &quot;{}&quot;", t)?;
}
// \b
if let Some(ref t) = self.entry_bookmark_name {
instr = format!("{} \\b &quot;{}&quot;", instr, t);
write!(raw, " \\b &quot;{}&quot;", t)?;
}
// \c
if let Some(ref t) = self.caption_label_including_numbers {
instr = format!("{} \\c &quot;{}&quot;", instr, t);
write!(raw, " \\c &quot;{}&quot;", t)?;
}
// \d
if let Some(ref t) = self.sequence_and_page_numbers_separator {
instr = format!("{} \\d &quot;{}&quot;", instr, t);
write!(raw, " \\d &quot;{}&quot;", t)?;
}
// \f
if let Some(ref t) = self.tc_field_identifier {
instr = format!("{} \\f &quot;{}&quot;", instr, t);
write!(raw, " \\f &quot;{}&quot;", t)?;
}
// \l
if let Some(range) = self.tc_field_level_range {
instr = format!("{} \\l &quot;{}-{}&quot;", instr, range.0, range.1);
write!(raw, " \\l &quot;{}-{}&quot;", range.0, range.1)?;
}
// \n
if let Some(range) = self.omit_page_numbers_level_range {
instr = format!("{} \\n &quot;{}-{}&quot;", instr, range.0, range.1);
write!(raw, " \\n &quot;{}-{}&quot;", range.0, range.1)?;
}
// \o
if let Some(range) = self.heading_styles_range {
instr = format!("{} \\o &quot;{}-{}&quot;", instr, range.0, range.1);
write!(raw, " \\o &quot;{}-{}&quot;", range.0, range.1)?;
}
// \p
if let Some(ref t) = self.entry_and_page_number_separator {
instr = format!("{} \\p &quot;{}&quot;", instr, t);
write!(raw, " \\p &quot;{}&quot;", t)?;
}
// \s
if let Some(ref t) = self.seq_field_identifier_for_prefix {
instr = format!("{} \\s &quot;{}&quot;", instr, t);
write!(raw, " \\s &quot;{}&quot;", t)?;
}
// \t
@ -220,35 +228,35 @@ impl BuildXML for InstrToC {
.map(|s| format!("{},{}", (s.0).0, (s.0).1))
.collect::<Vec<String>>()
.join(",");
instr = format!("{} \\t &quot;{}&quot;", instr, s);
write!(raw, " \\t &quot;{}&quot;", 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()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.is_lgl().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).is_lgl()?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.i().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).i()?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.i_cs().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).i_cs()?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.justification(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.justification(&self.val)?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:lvl w:ilvl="1"><w:start w:val="1" /><w:numFmt w:val="decimal" /><w:lvlText w:val="%4." /><w:lvlJc w:val="left" /><w:pPr><w:rPr /></w:pPr><w:rPr /><w:suff w:val="space" />
</w:lvl>"#
r#"<w:lvl w:ilvl="1"><w:start w:val="1" /><w:numFmt w:val="decimal" /><w:lvlText w:val="%4." /><w:lvlJc w:val="left" /><w:pPr><w:rPr /></w:pPr><w:rPr /><w:suff w:val="space" /></w:lvl>"#
);
}
#[test]

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.level_justification(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.level_justification(&self.val)?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:lvlOverride w:ilvl="1">
<w:startOverride w:val="2" />
</w:lvlOverride>"#
r#"<w:lvlOverride w:ilvl="1"><w:startOverride w:val="2" /></w:lvlOverride>"#
);
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
let v = format!("{}", &self.val);
b.level_restart(&v).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.level_restart(&format!("{}", &self.val))?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.level_text(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).level_text(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.line_spacing(
self.before,
self.after,
self.line,
self.before_lines,
self.after_lines,
self.line_rule,
)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.link(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).link(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
// Ignore for now
vec![]
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
// Ignore for now
Ok(stream)
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.name(&self.name).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).name(&self.name)?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.next(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).next(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
let r = Run::new()
impl BuildXML for NumPages {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<u8> {
self.inner_build()
}
}
impl BuildXML for Box<NumPages> {
fn build(&self) -> Vec<u8> {
self.inner_build()
.add_field_char(FieldCharType::End, false)
.build_to(stream)
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.number_format(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.number_format(&self.val)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:num w:numId="0">
<w:abstractNumId w:val="2" />
</w:num>"#
r#"<w:num w:numId="0"><w:abstractNumId w:val="2" /></w:num>"#
);
}
#[test]
@ -74,12 +76,7 @@ mod tests {
let b = c.overrides(overrides).build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:num w:numId="0">
<w:abstractNumId w:val="2" /><w:lvlOverride w:ilvl="0">
<w:startOverride w:val="1" />
</w:lvlOverride><w:lvlOverride w:ilvl="1">
<w:startOverride w:val="1" />
</w:lvlOverride></w:num>"#
r#"<w:num w:numId="0"><w:abstractNumId w:val="2" /><w:lvlOverride w:ilvl="0"><w:startOverride w:val="1" /></w:lvlOverride><w:lvlOverride w:ilvl="1"><w:startOverride w:val="1" /></w:lvlOverride></w:num>"#
);
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.num_id(self.id).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).num_id(self.id)?.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.open_numbering_property()
.add_optional_child(&self.id)
.add_optional_child(&self.level)
.close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_numbering_property()?
.add_optional_child(&self.id)?
.add_optional_child(&self.level)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new()
.outline_lvl(self.v)
// .close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.outline_lvl(self.v)?
// .close()?
.into_inner()
}
}

View File

@ -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.
// <w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0"/>
@ -53,8 +54,11 @@ impl PageMargin {
}
impl BuildXML for PageMargin {
fn build(&self) -> Vec<u8> {
XMLBuilder::new()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
let r = Run::new()
impl BuildXML for PageNum {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<u8> {
self.inner_build()
}
}
impl BuildXML for Box<PageNum> {
fn build(&self) -> Vec<u8> {
self.inner_build()
.add_field_char(FieldCharType::End, false)
.build_to(stream)
}
}

View File

@ -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<u8> {
XMLBuilder::new()
.page_num_type(self.start, self.chap_style.clone())
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.page_num_type(self.start, self.chap_style.clone())?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<u8> {
XMLBuilder::new()
.open_paragraph(&self.id)
.add_child(&self.property)
.add_children(&self.children)
.close()
.build()
}
}
impl BuildXML for Box<Paragraph> {
fn build(&self) -> Vec<u8> {
Paragraph::build(self)
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:commentRangeStart w:id="1" /><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r><w:r>
<w:rPr />
</w:r>
<w:commentRangeEnd w:id="1" />
<w:r>
<w:commentReference w:id="1" />
</w:r></w:p>"#
r#"<w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:commentRangeStart w:id="1" /><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r><w:r><w:rPr /></w:r><w:commentRangeEnd w:id="1" /><w:r><w:commentReference w:id="1" /></w:r></w:p>"#
);
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<ParagraphBorder>,
}
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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}
}

View File

@ -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<u8> {
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<u8> {
inner_build(self)
}
}
impl BuildXML for Box<ParagraphProperty> {
fn build(&self) -> Vec<u8> {
inner_build(self)
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:pPr><w:rPr /><w:keepNext />
</w:pPr>"#
r#"<w:pPr><w:rPr /><w:keepNext /></w:pPr>"#
);
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.open_paragraph_property_default()
.add_child(&self.paragraph_property)
.close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_paragraph_property_default()?
.add_child(&self.paragraph_property)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new().paragraph_style(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.paragraph_style(&self.val)?
.into_inner()
}
}

View File

@ -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<u8>,
// 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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id="0" name="" />
<pic:cNvPicPr>
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed="rIdImage123" />
<a:srcRect />
<a:stretch>
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode="auto">
<a:xfrm rot="0">
<a:off x="0" y="0" />
<a:ext cx="3048000" cy="2286000" />
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic>"#
r#"<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="" /><pic:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1" /></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImage123" /><a:srcRect /><a:stretch><a:fillRect /></a:stretch></pic:blipFill><pic:spPr bwMode="auto"><a:xfrm rot="0"><a:off x="0" y="0" /><a:ext cx="3048000" cy="2286000" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom></pic:spPr></pic:pic>"#
);
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.ptab(self.alignment, self.relative_to, self.leader)
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.ptab(self.alignment, self.relative_to, self.leader)?
.into_inner()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.q_format().build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).q_format()?.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_run()?
.add_child(&self.run_property)?
.add_children(&self.children)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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()
}
}

View File

@ -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<u8> {
let b = XMLBuilder::new();
b.open_run_property_default()
.add_child(&self.run_property)
.close()
.build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream)
.open_run_property_default()?
.add_child(&self.run_property)?
.close()?
.into_inner()
}
}

View File

@ -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<u8> {
XMLBuilder::new().run_style(&self.val).build()
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
XMLBuilder::from(stream).run_style(&self.val)?.into_inner()
}
}

View File

@ -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<u8> {
fn build_to<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:p w14:paraId="12345678">
<w:pPr><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" />
</w:sectPr></w:pPr>
</w:p>"#
r#"<w:p w14:paraId="12345678"><w:pPr><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /></w:sectPr></w:pPr></w:p>"#
);
}
}

View File

@ -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<u8> {
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<W: Write>(
&self,
stream: xml::writer::EventWriter<W>,
) -> xml::writer::Result<xml::writer::EventWriter<W>> {
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#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" />
<w:textDirection w:val="tbRl" />
</w:sectPr>"#
r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /><w:textDirection w:val="tbRl" /></w:sectPr>"#
)
}
@ -255,8 +250,7 @@ mod tests {
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" />
</w:sectPr>"#
r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /></w:sectPr>"#
);
}
@ -276,9 +270,7 @@ mod tests {
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" />
<w:titlePg />
</w:sectPr>"#
r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /><w:titlePg /></w:sectPr>"#
);
}
}

Some files were not shown because too many files have changed in this diff Show More