docx_rs/reader/
numberings.rs

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