feat: impl sdt writer (#380)
parent
ad229e91ad
commit
caa61e9947
|
@ -0,0 +1,16 @@
|
||||||
|
use docx_rs::*;
|
||||||
|
|
||||||
|
pub fn main() -> Result<(), DocxError> {
|
||||||
|
let path = std::path::Path::new("./output/sdt.docx");
|
||||||
|
let file = std::fs::File::create(&path).unwrap();
|
||||||
|
let p = Paragraph::new().add_run(
|
||||||
|
Run::new()
|
||||||
|
.add_text("Hello")
|
||||||
|
.fonts(RunFonts::new().ascii("Arial")),
|
||||||
|
);
|
||||||
|
Docx::new()
|
||||||
|
.add_structured_data_tag(StructuredDataTag::new().add_paragraph(p))
|
||||||
|
.build()
|
||||||
|
.pack(file)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ pub enum DocumentChild {
|
||||||
BookmarkEnd(BookmarkEnd),
|
BookmarkEnd(BookmarkEnd),
|
||||||
CommentStart(Box<CommentRangeStart>),
|
CommentStart(Box<CommentRangeStart>),
|
||||||
CommentEnd(CommentRangeEnd),
|
CommentEnd(CommentRangeEnd),
|
||||||
|
StructuredDataTag(StructuredDataTag),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DocumentChild {
|
impl Serialize for DocumentChild {
|
||||||
|
@ -65,6 +66,12 @@ impl Serialize for DocumentChild {
|
||||||
t.serialize_field("data", r)?;
|
t.serialize_field("data", r)?;
|
||||||
t.end()
|
t.end()
|
||||||
}
|
}
|
||||||
|
DocumentChild::StructuredDataTag(ref r) => {
|
||||||
|
let mut t = serializer.serialize_struct("StructuredDataTag", 2)?;
|
||||||
|
t.serialize_field("type", "structuredDataTag")?;
|
||||||
|
t.serialize_field("data", r)?;
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,6 +186,14 @@ impl Document {
|
||||||
self.section_property = self.section_property.even_footer(h, rid);
|
self.section_property = self.section_property.even_footer(h, rid);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Self {
|
||||||
|
if t.has_numbering {
|
||||||
|
self.has_numbering = true
|
||||||
|
}
|
||||||
|
self.children.push(DocumentChild::StructuredDataTag(t));
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildXML for DocumentChild {
|
impl BuildXML for DocumentChild {
|
||||||
|
@ -190,6 +205,7 @@ impl BuildXML for DocumentChild {
|
||||||
DocumentChild::BookmarkEnd(v) => v.build(),
|
DocumentChild::BookmarkEnd(v) => v.build(),
|
||||||
DocumentChild::CommentStart(v) => v.build(),
|
DocumentChild::CommentStart(v) => v.build(),
|
||||||
DocumentChild::CommentEnd(v) => v.build(),
|
DocumentChild::CommentEnd(v) => v.build(),
|
||||||
|
DocumentChild::StructuredDataTag(v) => v.build(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ mod doc_id;
|
||||||
mod doc_var;
|
mod doc_var;
|
||||||
mod drawing;
|
mod drawing;
|
||||||
mod font;
|
mod font;
|
||||||
|
mod footer_reference;
|
||||||
mod grid_span;
|
mod grid_span;
|
||||||
mod header_reference;
|
mod header_reference;
|
||||||
mod footer_reference;
|
|
||||||
mod highlight;
|
mod highlight;
|
||||||
mod indent;
|
mod indent;
|
||||||
mod indent_level;
|
mod indent_level;
|
||||||
|
@ -62,6 +62,7 @@ mod section;
|
||||||
mod section_property;
|
mod section_property;
|
||||||
mod shading;
|
mod shading;
|
||||||
mod start;
|
mod start;
|
||||||
|
mod structured_data_tag;
|
||||||
mod style;
|
mod style;
|
||||||
mod sz;
|
mod sz;
|
||||||
mod sz_cs;
|
mod sz_cs;
|
||||||
|
@ -120,9 +121,9 @@ pub use doc_id::*;
|
||||||
pub use doc_var::*;
|
pub use doc_var::*;
|
||||||
pub use drawing::*;
|
pub use drawing::*;
|
||||||
pub use font::*;
|
pub use font::*;
|
||||||
|
pub use footer_reference::*;
|
||||||
pub use grid_span::*;
|
pub use grid_span::*;
|
||||||
pub use header_reference::*;
|
pub use header_reference::*;
|
||||||
pub use footer_reference::*;
|
|
||||||
pub use highlight::*;
|
pub use highlight::*;
|
||||||
pub use indent::*;
|
pub use indent::*;
|
||||||
pub use indent_level::*;
|
pub use indent_level::*;
|
||||||
|
@ -159,6 +160,7 @@ pub use section::*;
|
||||||
pub use section_property::*;
|
pub use section_property::*;
|
||||||
pub use shading::*;
|
pub use shading::*;
|
||||||
pub use start::*;
|
pub use start::*;
|
||||||
|
pub use structured_data_tag::*;
|
||||||
pub use style::*;
|
pub use style::*;
|
||||||
pub use sz::*;
|
pub use sz::*;
|
||||||
pub use sz_cs::*;
|
pub use sz_cs::*;
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
use serde::ser::{SerializeStruct, Serializer};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::documents::BuildXML;
|
||||||
|
// use crate::types::*;
|
||||||
|
use crate::xml_builder::*;
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StructuredDataTag {
|
||||||
|
pub children: Vec<StructuredDataTagChild>,
|
||||||
|
pub has_numbering: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StructuredDataTag {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
children: Vec::new(),
|
||||||
|
has_numbering: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum StructuredDataTagChild {
|
||||||
|
Run(Box<Run>),
|
||||||
|
Paragraph(Box<Paragraph>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildXML for StructuredDataTagChild {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
StructuredDataTagChild::Run(v) => v.build(),
|
||||||
|
StructuredDataTagChild::Paragraph(v) => v.build(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for StructuredDataTagChild {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
StructuredDataTagChild::Run(ref r) => {
|
||||||
|
let mut t = serializer.serialize_struct("Run", 2)?;
|
||||||
|
t.serialize_field("type", "run")?;
|
||||||
|
t.serialize_field("data", r)?;
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
StructuredDataTagChild::Paragraph(ref r) => {
|
||||||
|
let mut t = serializer.serialize_struct("Paragraph", 2)?;
|
||||||
|
t.serialize_field("type", "paragraph")?;
|
||||||
|
t.serialize_field("data", r)?;
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructuredDataTag {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_run(mut self, run: Run) -> Self {
|
||||||
|
self.children
|
||||||
|
.push(StructuredDataTagChild::Run(Box::new(run)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_paragraph(mut self, p: Paragraph) -> Self {
|
||||||
|
if p.has_numbering {
|
||||||
|
self.has_numbering = true
|
||||||
|
}
|
||||||
|
self.children
|
||||||
|
.push(StructuredDataTagChild::Paragraph(Box::new(p)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildXML for StructuredDataTag {
|
||||||
|
fn build(&self) -> Vec<u8> {
|
||||||
|
XMLBuilder::new()
|
||||||
|
.open_structured_tag()
|
||||||
|
.open_structured_tag_property()
|
||||||
|
.close()
|
||||||
|
.open_structured_tag_content()
|
||||||
|
.add_children(&self.children)
|
||||||
|
.close()
|
||||||
|
.close()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[cfg(test)]
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sdt() {
|
||||||
|
let b = StructuredDataTag::new()
|
||||||
|
.add_run(Run::new().add_text("Hello"))
|
||||||
|
.build();
|
||||||
|
assert_eq!(
|
||||||
|
str::from_utf8(&b).unwrap(),
|
||||||
|
r#"<w:sdt>
|
||||||
|
<w:sdtPr />
|
||||||
|
<w:sdtContent><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:sdtContent>
|
||||||
|
</w:sdt>"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -191,6 +191,16 @@ impl Docx {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Docx {
|
||||||
|
if t.has_numbering {
|
||||||
|
// If this document has numbering, set numberings.xml to document_rels.
|
||||||
|
// This is because numberings.xml without numbering cause an error on word online.
|
||||||
|
self.document_rels.has_numberings = true;
|
||||||
|
}
|
||||||
|
self.document = self.document.add_structured_data_tag(t);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Docx {
|
pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Docx {
|
||||||
self.document = self.document.add_bookmark_start(id, name);
|
self.document = self.document.add_bookmark_start(id, name);
|
||||||
self
|
self
|
||||||
|
|
|
@ -72,6 +72,11 @@ impl XMLBuilder {
|
||||||
open!(open_paragraph, "w:p", "w14:paraId");
|
open!(open_paragraph, "w:p", "w14:paraId");
|
||||||
open!(open_paragraph_property, "w:pPr");
|
open!(open_paragraph_property, "w:pPr");
|
||||||
open!(open_doc_defaults, "w:docDefaults");
|
open!(open_doc_defaults, "w:docDefaults");
|
||||||
|
|
||||||
|
open!(open_structured_tag, "w:sdt");
|
||||||
|
open!(open_structured_tag_content, "w:sdtContent");
|
||||||
|
open!(open_structured_tag_property, "w:sdtPr");
|
||||||
|
|
||||||
// i.e. <w:outlineLvl ...>
|
// i.e. <w:outlineLvl ...>
|
||||||
closed_with_usize!(outline_lvl, "w:outlineLvl");
|
closed_with_usize!(outline_lvl, "w:outlineLvl");
|
||||||
// i.e. <w:name ... >
|
// i.e. <w:name ... >
|
||||||
|
|
Loading…
Reference in New Issue