Skip to main content

docx_rs/reader/
numberings.rs

1use super::*;
2use crate::reader::{FromXML, ReaderError};
3use std::io::Read;
4
5use std::str::FromStr;
6
7impl FromXML for Numberings {
8    fn from_xml<R: Read>(reader: R) -> Result<Self, ReaderError> {
9        let mut parser = EventReader::new(reader);
10        let mut nums = Self::default();
11        loop {
12            let e = parser.next_event();
13            match e {
14                Ok(XmlEvent::StartElement {
15                    attributes, name, ..
16                }) => {
17                    let e = XMLElement::from_str(&name.local_name).unwrap();
18                    match e {
19                        XMLElement::AbstractNumbering => {
20                            let mut id = 0;
21                            for a in attributes {
22                                let local_name = &a.name.local_name;
23                                if local_name == "abstractNumId" {
24                                    id = usize::from_str(&a.value)?;
25                                }
26                            }
27                            let mut abs_num = AbstractNumbering::new(id);
28                            loop {
29                                let e = parser.next_event();
30                                match e {
31                                    Ok(XmlEvent::StartElement {
32                                        attributes, name, ..
33                                    }) => {
34                                        let e = XMLElement::from_str(&name.local_name).unwrap();
35                                        match e {
36                                            XMLElement::Level => {
37                                                let l = Level::read(&mut parser, &attributes)?;
38                                                abs_num = abs_num.add_level(l);
39                                            }
40                                            XMLElement::StyleLink => {
41                                                abs_num = abs_num.style_link(&attributes[0].value)
42                                            }
43                                            XMLElement::NumStyleLink => {
44                                                abs_num =
45                                                    abs_num.num_style_link(&attributes[0].value)
46                                            }
47                                            _ => {}
48                                        }
49                                    }
50                                    Ok(XmlEvent::EndElement { name, .. }) => {
51                                        let e = XMLElement::from_str(&name.local_name).unwrap();
52                                        if let XMLElement::AbstractNumbering = e {
53                                            nums = nums.add_abstract_numbering(abs_num);
54                                            break;
55                                        }
56                                    }
57                                    _ => {}
58                                }
59                            }
60                            continue;
61                        }
62                        XMLElement::Num => {
63                            let mut id = 0;
64                            for a in attributes {
65                                let local_name = &a.name.local_name;
66                                if local_name == "numId" {
67                                    id = usize::from_str(&a.value)?;
68                                }
69                            }
70                            let mut abs_num_id = 0;
71                            let mut level_overrides = vec![];
72
73                            loop {
74                                let e = parser.next_event();
75                                match e {
76                                    Ok(XmlEvent::StartElement {
77                                        attributes, name, ..
78                                    }) => {
79                                        let e = XMLElement::from_str(&name.local_name).unwrap();
80                                        match e {
81                                            XMLElement::AbstractNumberingId => {
82                                                abs_num_id = usize::from_str(&attributes[0].value)?
83                                            }
84                                            XMLElement::LvlOverride => {
85                                                if let Ok(o) =
86                                                    LevelOverride::read(&mut parser, &attributes)
87                                                {
88                                                    level_overrides.push(o);
89                                                }
90                                            }
91                                            _ => {}
92                                        }
93                                    }
94                                    Ok(XmlEvent::EndElement { name, .. }) => {
95                                        let e = XMLElement::from_str(&name.local_name).unwrap();
96                                        if let XMLElement::Num = e {
97                                            let num = Numbering::new(id, abs_num_id);
98                                            nums =
99                                                nums.add_numbering(num.overrides(level_overrides));
100                                            break;
101                                        }
102                                    }
103                                    _ => {}
104                                }
105                            }
106                            continue;
107                        }
108                        _ => {}
109                    }
110                }
111                Ok(XmlEvent::EndElement { name, .. }) => {
112                    let e = XMLElement::from_str(&name.local_name).unwrap();
113                    if let XMLElement::Numbering = e {
114                        break;
115                    }
116                }
117                Ok(XmlEvent::EndDocument) => break,
118                Err(_) => return Err(ReaderError::XMLReadError),
119                _ => {}
120            }
121        }
122        Ok(nums)
123    }
124}
125
126#[cfg(test)]
127mod tests {
128
129    use super::*;
130    use crate::types::*;
131    #[cfg(test)]
132    use pretty_assertions::assert_eq;
133
134    #[test]
135    fn test_numberings_from_xml() {
136        let xml = r#"<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
137            xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" >
138    <w:abstractNum w:abstractNumId="0" w15:restartNumberingAfterBreak="0">
139        <w:multiLevelType w:val="hybridMultilevel"></w:multiLevelType>
140        <w:lvl w:ilvl="0" w15:tentative="1">
141            <w:start w:val="1"></w:start>
142            <w:numFmt w:val="bullet"></w:numFmt>
143            <w:lvlText w:val="●"></w:lvlText>
144            <w:lvlJc w:val="left"></w:lvlJc>
145            <w:pPr>
146                <w:ind w:left="720" w:hanging="360"></w:ind>
147            </w:pPr>
148            <w:rPr></w:rPr>
149        </w:lvl>
150    </w:abstractNum>
151    <w:num w:numId="1">
152        <w:abstractNumId w:val="0"></w:abstractNumId>
153    </w:num>
154</w:numbering>"#;
155        let n = Numberings::from_xml(xml.as_bytes()).unwrap();
156        let mut nums = Numberings::new();
157        nums = nums
158            .add_abstract_numbering(
159                AbstractNumbering::new(0).add_level(
160                    Level::new(
161                        0,
162                        Start::new(1),
163                        NumberFormat::new("bullet"),
164                        LevelText::new("●"),
165                        LevelJc::new("left"),
166                    )
167                    .indent(
168                        Some(720),
169                        Some(SpecialIndentType::Hanging(360)),
170                        None,
171                        None,
172                    ),
173                ),
174            )
175            .add_numbering(Numbering::new(1, 0));
176        assert_eq!(n, nums)
177    }
178
179    #[test]
180    fn test_numberings_from_xml_with_num_style_link() {
181        let xml = r#"<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
182            xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" >
183    <w:abstractNum w:abstractNumId="0">
184        <w:multiLevelType w:val="hybridMultilevel"/>
185        <w:numStyleLink w:val="style1"/>
186    </w:abstractNum>
187    <w:num w:numId="1">
188        <w:abstractNumId w:val="0"></w:abstractNumId>
189    </w:num>
190</w:numbering>"#;
191        let n = Numberings::from_xml(xml.as_bytes()).unwrap();
192        let mut nums = Numberings::new();
193        nums = nums
194            .add_abstract_numbering(AbstractNumbering::new(0).num_style_link("style1"))
195            .add_numbering(Numbering::new(1, 0));
196        assert_eq!(n, nums)
197    }
198
199    #[test]
200    fn test_numberings_from_xml_with_style_link() {
201        let xml = r#"<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
202            xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" >
203    <w:abstractNum w:abstractNumId="0">
204        <w:multiLevelType w:val="hybridMultilevel"/>
205        <w:styleLink w:val="style1"/>
206    </w:abstractNum>
207    <w:num w:numId="1">
208        <w:abstractNumId w:val="0"></w:abstractNumId>
209    </w:num>
210</w:numbering>"#;
211        let n = Numberings::from_xml(xml.as_bytes()).unwrap();
212        let mut nums = Numberings::new();
213        nums = nums
214            .add_abstract_numbering(AbstractNumbering::new(0).style_link("style1"))
215            .add_numbering(Numbering::new(1, 0));
216        assert_eq!(n, nums)
217    }
218
219    #[test]
220    fn test_numberings_from_xml_with_override() {
221        let xml = r#"<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
222            xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" >
223    <w:abstractNum w:abstractNumId="0">
224        <w:multiLevelType w:val="hybridMultilevel"/>
225    </w:abstractNum>
226    <w:num w:numId="1">
227        <w:abstractNumId w:val="0"></w:abstractNumId>
228        <w:lvlOverride w:ilvl="0">
229          <w:startOverride w:val="1"/>
230        </w:lvlOverride>
231        <w:lvlOverride w:ilvl="1">
232          <w:startOverride w:val="1"/>
233        </w:lvlOverride>
234    </w:num>
235</w:numbering>"#;
236        let n = Numberings::from_xml(xml.as_bytes()).unwrap();
237        let mut nums = Numberings::new();
238        let overrides = vec![
239            LevelOverride::new(0).start(1),
240            LevelOverride::new(1).start(1),
241        ];
242        let num = Numbering::new(1, 0).overrides(overrides);
243        nums = nums
244            .add_abstract_numbering(AbstractNumbering::new(0))
245            .add_numbering(num);
246        assert_eq!(n, nums)
247    }
248}