1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; use super::{Paragraph, SectionProperty, Table}; use crate::documents::BuildXML; use crate::xml_builder::*; #[derive(Debug, Clone, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Document { pub children: Vec<DocumentChild>, pub section_property: SectionProperty, pub has_numbering: bool, } #[derive(Debug, Clone, PartialEq)] pub enum DocumentChild { Paragraph(Paragraph), Table(Table), } impl Serialize for DocumentChild { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { match *self { DocumentChild::Paragraph(ref p) => { let mut t = serializer.serialize_struct("Paragraph", 2)?; t.serialize_field("type", "paragraph")?; t.serialize_field("data", p)?; t.end() } DocumentChild::Table(ref c) => { let mut t = serializer.serialize_struct("Table", 2)?; t.serialize_field("type", "table")?; t.serialize_field("data", c)?; t.end() } } } } impl Default for Document { fn default() -> Self { Self { children: Vec::new(), section_property: SectionProperty::new(), has_numbering: false, } } } impl Document { pub fn new() -> Document { Default::default() } pub fn add_paragraph(mut self, p: Paragraph) -> Self { if p.has_numbering { self.has_numbering = true } self.children.push(DocumentChild::Paragraph(p)); self } pub fn add_table(mut self, t: Table) -> Self { if t.has_numbering { self.has_numbering = true } self.children.push(DocumentChild::Table(t)); self } } impl BuildXML for Document { fn build(&self) -> Vec<u8> { let mut b = XMLBuilder::new() .declaration(Some(true)) .open_document() .open_body(); for c in &self.children { match c { DocumentChild::Paragraph(p) => b = b.add_child(p), DocumentChild::Table(t) => b = b.add_child(t), } } b.add_child(&self.section_property).close().close().build() } } #[cfg(test)] mod tests { use super::super::Run; use super::*; #[cfg(test)] use pretty_assertions::assert_eq; use std::str; #[test] fn test_document() { let b = Document::new() .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))) .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" mc:Ignorable="w14 wp14"> <w:body><w:p><w:pPr><w:pStyle w:val="Normal" /><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:docGrid w:type="lines" w:linePitch="360" /> </w:sectPr></w:body> </w:document>"# ); } }