Skip to main content

docx_rs/documents/elements/
abstract_numbering.rs

1use crate::documents::{BuildXML, Level};
2use crate::xml_builder::*;
3use std::io::Write;
4
5use serde::Serialize;
6
7#[derive(Debug, Clone, PartialEq, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct AbstractNumbering {
10    pub id: usize,
11    pub style_link: Option<String>,
12    pub num_style_link: Option<String>,
13    pub levels: Vec<Level>,
14  #[serde(skip_serializing_if = "Option::is_none")]
15  pub multi_level_type: Option<String>,
16}
17
18impl AbstractNumbering {
19    pub fn new(id: usize) -> Self {
20        Self {
21            id,
22            style_link: None,
23            num_style_link: None,
24            levels: vec![],
25            multi_level_type: None,
26        }
27    }
28
29    pub fn add_level(mut self, level: Level) -> Self {
30        self.levels.push(level);
31        self
32    }
33
34    pub fn num_style_link(mut self, link: impl Into<String>) -> Self {
35        self.num_style_link = Some(link.into());
36        self
37    }
38
39    pub fn style_link(mut self, link: impl Into<String>) -> Self {
40        self.style_link = Some(link.into());
41        self
42    }
43}
44
45impl BuildXML for AbstractNumbering {
46    fn build_to<W: Write>(
47        &self,
48        stream: xml::writer::EventWriter<W>,
49    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
50        let mut builder = XMLBuilder::from(stream)  
51            .open_abstract_num(&self.id.to_string())?;  
52          
53        // 添加 multiLevelType 元素(如果存在)  
54        if let Some(ref multi_level_type) = self.multi_level_type {  
55            builder = builder.multi_level_type(multi_level_type)?;  
56        }  
57          
58        builder  
59            .add_children(&self.levels)?  
60            .close()?  
61            .into_inner()  
62    }
63}
64
65#[cfg(test)]
66mod tests {
67
68    use super::*;
69    #[cfg(test)]
70    use crate::documents::{Level, LevelJc, LevelText, NumberFormat, Start};
71    use pretty_assertions::assert_eq;
72    use std::str;
73
74    #[test]
75    fn test_numbering() {
76        let mut c = AbstractNumbering::new(0);
77        c = c.add_level(Level::new(
78            1,
79            Start::new(1),
80            NumberFormat::new("decimal"),
81            LevelText::new("%4."),
82            LevelJc::new("left"),
83        ));
84        let b = c.build();
85        assert_eq!(
86            str::from_utf8(&b).unwrap(),
87            r#"<w:abstractNum w:abstractNumId="0"><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:lvl></w:abstractNum>"#
88        );
89    }
90
91    #[test]
92    fn test_numbering_json() {
93        let mut c = AbstractNumbering::new(0);
94        c = c
95            .add_level(Level::new(
96                1,
97                Start::new(1),
98                NumberFormat::new("decimal"),
99                LevelText::new("%4."),
100                LevelJc::new("left"),
101            ))
102            .num_style_link("style1");
103        assert_eq!(
104            serde_json::to_string(&c).unwrap(),
105            r#"{"id":0,"styleLink":null,"numStyleLink":"style1","levels":[{"level":1,"start":1,"format":"decimal","text":"%4.","jc":"left","paragraphProperty":{"runProperty":{},"tabs":[]},"runProperty":{},"suffix":"tab","pstyle":null,"levelRestart":null}]}"#,
106        );
107    }
108}