From 3e154d69049f56ff44da021f99db432bdd06ce10 Mon Sep 17 00:00:00 2001 From: bokuweb Date: Tue, 5 Nov 2019 18:03:23 +0900 Subject: [PATCH] feat: Add rels --- docx-core/fixtures/hello/_rels/.rels | 5 +- docx-core/src/documents/content_types.rs | 6 +-- docx-core/src/documents/mod.rs | 9 ++-- docx-core/src/documents/rels.rs | 54 +++++++++++++++++++ docx-core/src/documents/xml_document.rs | 6 ++- docx-core/src/lib.rs | 2 + docx-core/src/xml_builder/declaration.rs | 33 ++++++++++++ docx-core/src/xml_builder/macros.rs | 37 +++++++++++++ .../xml_builder.rs => xml_builder/mod.rs} | 45 ++++++++++++---- docx-core/src/xml_builder/relationship.rs | 41 ++++++++++++++ 10 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 docx-core/src/documents/rels.rs create mode 100644 docx-core/src/xml_builder/declaration.rs create mode 100644 docx-core/src/xml_builder/macros.rs rename docx-core/src/{documents/xml_builder.rs => xml_builder/mod.rs} (60%) create mode 100644 docx-core/src/xml_builder/relationship.rs diff --git a/docx-core/fixtures/hello/_rels/.rels b/docx-core/fixtures/hello/_rels/.rels index f0b72e7..e13b32e 100644 --- a/docx-core/fixtures/hello/_rels/.rels +++ b/docx-core/fixtures/hello/_rels/.rels @@ -1,3 +1,6 @@ - + + + + \ No newline at end of file diff --git a/docx-core/src/documents/content_types.rs b/docx-core/src/documents/content_types.rs index 837ca2a..5cadba2 100644 --- a/docx-core/src/documents/content_types.rs +++ b/docx-core/src/documents/content_types.rs @@ -1,4 +1,4 @@ -use super::xml_builder::*; +use crate::xml_builder::*; pub struct ContentTypes {} @@ -9,7 +9,7 @@ impl ContentTypes { pub fn build(&self) -> Vec { let b = XMLBuilder::new(); - b.add_declaration() + b.declaration() .open_types("http://schemas.openxmlformats.org/package/2006/content-types") .add_override( "/_rels/.rels", @@ -60,7 +60,7 @@ mod tests { let b = c.build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#" + r#" diff --git a/docx-core/src/documents/mod.rs b/docx-core/src/documents/mod.rs index d7e9c66..9627d62 100644 --- a/docx-core/src/documents/mod.rs +++ b/docx-core/src/documents/mod.rs @@ -1,16 +1,19 @@ -pub mod content_types; -mod xml_builder; +mod content_types; +mod rels; mod xml_document; use content_types::*; +use rels::*; pub(crate) struct Document { content_type: ContentTypes, + rels: Rels, } impl Document { pub fn new() -> Document { let content_type = ContentTypes::new(); - Document { content_type } + let rels = Rels::new(); + Document { content_type, rels } } } diff --git a/docx-core/src/documents/rels.rs b/docx-core/src/documents/rels.rs new file mode 100644 index 0000000..562cc08 --- /dev/null +++ b/docx-core/src/documents/rels.rs @@ -0,0 +1,54 @@ +use crate::xml_builder::*; + +pub struct Rels {} + +impl Rels { + pub fn new() -> Rels { + Rels {} + } + + pub fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.declaration() + .open_relationships("http://schemas.openxmlformats.org/package/2006/relationships") + .relationship( + "rId1", + "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", + "docProps/core.xml" + ) + .relationship( + "rId2", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties", + "docProps/app.xml" + ) + .relationship( + "rId3", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", + "word/document.xml" + ) + .close() + .build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use std::str; + + #[test] + fn test_build() { + let c = Rels::new(); + let b = c.build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#" + + + + +"# + ); + } +} diff --git a/docx-core/src/documents/xml_document.rs b/docx-core/src/documents/xml_document.rs index 5b05e4b..bd0ea69 100644 --- a/docx-core/src/documents/xml_document.rs +++ b/docx-core/src/documents/xml_document.rs @@ -2,11 +2,15 @@ use super::Document; pub(crate) struct XMLDocument { content_type: Vec, + rels: Vec, } impl From for XMLDocument { fn from(doc: Document) -> XMLDocument { let content_type = doc.content_type.build(); - XMLDocument { content_type } + XMLDocument { + content_type, + rels: vec![], + } } } diff --git a/docx-core/src/lib.rs b/docx-core/src/lib.rs index c5a0a49..c4806d9 100644 --- a/docx-core/src/lib.rs +++ b/docx-core/src/lib.rs @@ -1,6 +1,8 @@ mod documents; +mod xml_builder; use documents::*; +use xml_builder::*; use std::fs::File; use std::io::{self, Write}; diff --git a/docx-core/src/xml_builder/declaration.rs b/docx-core/src/xml_builder/declaration.rs new file mode 100644 index 0000000..84381ff --- /dev/null +++ b/docx-core/src/xml_builder/declaration.rs @@ -0,0 +1,33 @@ +use super::XMLBuilder; + +impl XMLBuilder { + // Build XML declaration + // i.e. + pub(crate) fn declaration(mut self) -> Self { + self.writer + .write(super::XmlEvent::StartDocument { + version: super::XmlVersion::Version10, + encoding: Some("UTF-8"), + standalone: None, + }) + .expect("should write to buf"); + self + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use std::str; + + #[test] + fn test_declaration() { + let b = XMLBuilder::new(); + let r = b.declaration().build(); + assert_eq!( + str::from_utf8(&r).unwrap(), + r#""# + ); + } +} diff --git a/docx-core/src/xml_builder/macros.rs b/docx-core/src/xml_builder/macros.rs new file mode 100644 index 0000000..90687cd --- /dev/null +++ b/docx-core/src/xml_builder/macros.rs @@ -0,0 +1,37 @@ +macro_rules! opened_el { + ($name: ident, $el_name: expr, $attr0: expr) => { + pub(crate) fn $name(mut self, arg0: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0)) + .expect("should write to buf"); + self + } + }; +} + +macro_rules! closed_el { + ($name: ident, $el_name: expr, $attr0: expr) => { + pub(crate) fn $name(mut self, arg0: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0)) + .expect("should write to buf"); + self.close() + } + }; + ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr) => { + pub(crate) fn $name(mut self, arg0: &str, arg1: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0).attr($attr1, arg1)) + .expect("should write to buf"); + self.close() + } + }; + ($name: ident, $el_name: expr, $attr0: expr, $attr1: expr, $attr2: expr) => { + pub(crate) fn $name(mut self, arg0: &str, arg1: &str, arg2: &str) -> Self { + self.writer + .write(super::XmlEvent::start_element($el_name).attr($attr0, arg0).attr($attr1, arg1).attr($attr2, arg2)) + .expect("should write to buf"); + self.close() + } + }; +} diff --git a/docx-core/src/documents/xml_builder.rs b/docx-core/src/xml_builder/mod.rs similarity index 60% rename from docx-core/src/documents/xml_builder.rs rename to docx-core/src/xml_builder/mod.rs index 0e8c175..16ca6bc 100644 --- a/docx-core/src/documents/xml_builder.rs +++ b/docx-core/src/xml_builder/mod.rs @@ -1,3 +1,9 @@ +#[macro_use] +mod macros; +mod declaration; +mod relationship; + +use xml::common::XmlVersion; use xml::writer::{EmitterConfig, EventWriter, XmlEvent}; pub struct XMLBuilder { @@ -14,17 +20,8 @@ impl XMLBuilder { XMLBuilder { writer } } - pub(crate) fn add_declaration(mut self) -> Self { - self.writer - .write( - XmlEvent::start_element("?xml") - .attr("version", "1.0") - .attr("encoding", "UTF-8"), - ) - .expect("should write to buf"); - self.close() - } - + // Build types element + // i.e. pub(crate) fn open_types(mut self, uri: &str) -> Self { self.writer .write(XmlEvent::start_element("Types").attr("xmlns", uri)) @@ -32,6 +29,8 @@ impl XMLBuilder { self } + // Build Override element + // i.e. pub(crate) fn add_override(mut self, name: &str, content_type: &str) -> Self { self.writer .write( @@ -43,6 +42,7 @@ impl XMLBuilder { self.close() } + // Close tag pub(crate) fn close(mut self) -> Self { self.writer .write(XmlEvent::end_element()) @@ -50,7 +50,30 @@ impl XMLBuilder { self } + // Write plain text + pub(crate) fn text(mut self, t: &str) -> Self { + self.writer.write(t).unwrap(); + self + } + pub(crate) fn build(self) -> Vec { self.writer.into_inner() } } + +#[cfg(test)] +mod tests { + + use super::*; + use std::str; + + #[test] + fn test_open_types() { + let b = XMLBuilder::new(); + let r = b.open_types("http://example").text("child").close().build(); + assert_eq!( + str::from_utf8(&r).unwrap(), + r#"child"# + ); + } +} diff --git a/docx-core/src/xml_builder/relationship.rs b/docx-core/src/xml_builder/relationship.rs new file mode 100644 index 0000000..eb9f509 --- /dev/null +++ b/docx-core/src/xml_builder/relationship.rs @@ -0,0 +1,41 @@ +use super::XMLBuilder; + +impl XMLBuilder { + // Build RelationShips element + // i.e. + opened_el!(open_relationships, "Relationships", "xmlns"); + + // Build Relationship + closed_el!(relationship, "Relationship", "Id", "Type", "Target"); +} + +#[cfg(test)] +mod tests { + + use super::XMLBuilder; + use std::str; + + #[test] + fn test_open_relationships() { + let b = XMLBuilder::new(); + let r = b + .open_relationships("http://example") + .text("child") + .close() + .build(); + assert_eq!( + str::from_utf8(&r).unwrap(), + r#"child"# + ); + } + + #[test] + fn test_relationship() { + let b = XMLBuilder::new(); + let r = b.relationship("rId1", "http://example", "core.xml").build(); + assert_eq!( + str::from_utf8(&r).unwrap(), + r#""# + ); + } +}