1use std::io::Read;
2use std::str::FromStr;
3
4use xml::attribute::OwnedAttribute;
5use xml::reader::{EventReader, XmlEvent};
6
7use super::*;
8
9use super::attributes::*;
10
11impl ElementReader for Paragraph {
12 fn read<R: Read>(
13 r: &mut EventReader<R>,
14 attrs: &[OwnedAttribute],
15 ) -> Result<Self, ReaderError> {
16 let mut p = Paragraph::new();
17 if let Some(para_id) = read(attrs, "paraId") {
18 p = p.id(para_id);
19 }
20 loop {
21 let e = r.next();
22 match e {
23 Ok(XmlEvent::StartElement {
24 attributes, name, ..
25 }) => {
26 let e = XMLElement::from_str(&name.local_name).unwrap();
27
28 match e {
29 XMLElement::Run => {
30 let run = Run::read(r, &attributes)?;
31 p = p.add_run(run);
32 continue;
33 }
34 XMLElement::Hyperlink => {
35 let link = Hyperlink::read(r, &attributes)?;
36 p = p.add_hyperlink(link);
37 continue;
38 }
39 XMLElement::Insert => {
40 let ins = Insert::read(r, &attributes)?;
41 p = p.add_insert(ins);
42 continue;
43 }
44 XMLElement::Delete => {
45 let del = Delete::read(r, &attributes)?;
46 p = p.add_delete(del);
47 continue;
48 }
49 XMLElement::BookmarkStart => {
50 let s = BookmarkStart::read(r, &attributes)?;
51 p = p.add_bookmark_start(s.id, s.name);
52 continue;
53 }
54 XMLElement::BookmarkEnd => {
55 let e = BookmarkEnd::read(r, &attributes)?;
56 p = p.add_bookmark_end(e.id);
57 continue;
58 }
59 XMLElement::CommentRangeStart => {
60 if let Some(id) = read(&attributes, "id") {
61 if let Ok(id) = usize::from_str(&id) {
62 let comment = Comment::new(id);
63 p = p.add_comment_start(comment);
64 }
65 }
66 continue;
67 }
68 XMLElement::CommentRangeEnd => {
69 if let Some(id) = read(&attributes, "id") {
70 if let Ok(id) = usize::from_str(&id) {
71 p = p.add_comment_end(id);
72 }
73 }
74 continue;
75 }
76 XMLElement::ParagraphProperty => {
78 if let Ok(pr) = ParagraphProperty::read(r, &attributes) {
79 p.has_numbering = pr.numbering_property.is_some();
80 p.property = pr;
81 }
82 continue;
83 }
84 _ => {}
85 }
86 }
87 Ok(XmlEvent::EndElement { name, .. }) => {
88 let e = XMLElement::from_str(&name.local_name).unwrap();
89 if e == XMLElement::Paragraph {
90 return Ok(p);
91 }
92 }
93 Err(_) => return Err(ReaderError::XMLReadError),
94 _ => {}
95 }
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102
103 use super::*;
104 use crate::types::*;
105 #[cfg(test)]
106 use pretty_assertions::assert_eq;
107
108 #[test]
109 fn test_read_indent() {
110 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
111 <w:p>
112 <w:pPr>
113 <w:ind w:left="1470" w:right="1270" w:hanging="0"/>
114 <w:rPr></w:rPr>
115 </w:pPr>
116 <w:r>
117 <w:rPr></w:rPr>
118 <w:t>a</w:t>
119 </w:r>
120 </w:p>
121</w:document>"#;
122 let mut parser = EventReader::new(c.as_bytes());
123 let p = Paragraph::read(&mut parser, &[]).unwrap();
124
125 assert_eq!(
126 p,
127 Paragraph {
128 id: "12345678".to_owned(),
129 children: vec![ParagraphChild::Run(Box::new(Run::new().add_text("a")))],
130 property: ParagraphProperty {
131 run_property: RunProperty::new(),
132 style: None,
133 numbering_property: None,
134 alignment: None,
135 indent: Some(Indent::new(
136 Some(1470),
137 Some(SpecialIndentType::Hanging(0)),
138 Some(1270),
139 None,
140 )),
141 line_spacing: None,
142 ..Default::default()
143 },
144 has_numbering: false,
145 }
146 );
147 }
148
149 #[test]
150 fn test_read_indent_start_chars() {
151 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
152 <w:p>
153 <w:pPr>
154 <w:ind w:startChars="100" />
155 <w:rPr></w:rPr>
156 </w:pPr>
157 <w:r>
158 <w:rPr></w:rPr>
159 <w:t>a</w:t>
160 </w:r>
161 </w:p>
162</w:document>"#;
163 let mut parser = EventReader::new(c.as_bytes());
164 let p = Paragraph::read(&mut parser, &[]).unwrap();
165
166 assert_eq!(
167 p,
168 Paragraph {
169 id: "12345678".to_owned(),
170 children: vec![ParagraphChild::Run(Box::new(Run::new().add_text("a")))],
171 property: ParagraphProperty {
172 run_property: RunProperty::new(),
173 style: None,
174 numbering_property: None,
175 alignment: None,
176 indent: Some(Indent::new(None, None, None, Some(100))),
177 line_spacing: None,
178 ..Default::default()
179 },
180 has_numbering: false,
181 }
182 );
183 }
184
185 #[test]
186 fn test_read_jc() {
187 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
188 <w:p>
189 <w:pPr>
190 <w:jc w:val="left"/>
191 </w:pPr>
192 </w:p>
193</w:document>"#;
194 let mut parser = EventReader::new(c.as_bytes());
195 let p = Paragraph::read(&mut parser, &[]).unwrap();
196
197 assert_eq!(
198 p,
199 Paragraph {
200 id: "12345678".to_owned(),
201 children: vec![],
202 property: ParagraphProperty {
203 run_property: RunProperty::new(),
204 style: None,
205 numbering_property: None,
206 alignment: Some(Justification::new(AlignmentType::Left.to_string())),
207 indent: None,
208 line_spacing: None,
209 ..Default::default()
210 },
211 has_numbering: false,
212 }
213 );
214 }
215
216 #[test]
217 fn test_read_numbering() {
218 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
219 <w:p>
220 <w:pPr>
221 <w:numPr>
222 <w:ilvl w:val="0"/>
223 <w:numId w:val="1"/>
224 </w:numPr>
225 </w:pPr>
226 </w:p>
227</w:document>"#;
228 let mut parser = EventReader::new(c.as_bytes());
229 let p = Paragraph::read(&mut parser, &[]).unwrap();
230 assert_eq!(
231 p,
232 Paragraph {
233 id: "12345678".to_owned(),
234 children: vec![],
235 property: ParagraphProperty {
236 run_property: RunProperty::new(),
237 style: None,
238 numbering_property: Some(
239 NumberingProperty::new().add_num(NumberingId::new(1), IndentLevel::new(0),)
240 ),
241 alignment: None,
242 indent: None,
243 line_spacing: None,
244 ..Default::default()
245 },
246 has_numbering: true,
247 }
248 );
249 }
250
251 #[test]
252 fn test_read_insert() {
253 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
254 <w:p>
255 <w:ins w:id="0" w:author="unknown" w:date="2019-11-15T14:19:04Z">
256 <w:r>
257 <w:rPr></w:rPr>
258 <w:t>W</w:t>
259 </w:r>
260 </w:ins>
261 </w:p>
262</w:document>"#;
263 let mut parser = EventReader::new(c.as_bytes());
264 let p = Paragraph::read(&mut parser, &[]).unwrap();
265 assert_eq!(
266 p,
267 Paragraph {
268 id: "12345678".to_owned(),
269 children: vec![ParagraphChild::Insert(
270 Insert::new(Run::new().add_text("W"))
271 .author("unknown")
272 .date("2019-11-15T14:19:04Z")
273 )],
274 property: ParagraphProperty {
275 run_property: RunProperty::new(),
276 style: None,
277 numbering_property: None,
278 alignment: None,
279 indent: None,
280 line_spacing: None,
281 ..Default::default()
282 },
283 has_numbering: false,
284 }
285 );
286 }
287
288 #[test]
289 fn test_read_delete() {
290 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
291 <w:p>
292 <w:del w:id="3" w:author="unknown" w:date="2019-11-15T14:19:04Z">
293 <w:r>
294 <w:rPr></w:rPr>
295 <w:delText xml:space="preserve">Hello </w:delText>
296 </w:r>
297 </w:del>
298 </w:p>
299</w:document>"#;
300 let mut parser = EventReader::new(c.as_bytes());
301 let p = Paragraph::read(&mut parser, &[]).unwrap();
302
303 assert_eq!(
304 p,
305 Paragraph {
306 id: "12345678".to_owned(),
307 children: vec![ParagraphChild::Delete(
308 Delete::new()
309 .add_run(Run::new().add_delete_text("Hello "))
310 .author("unknown")
311 .date("2019-11-15T14:19:04Z")
312 )],
313 property: ParagraphProperty {
314 run_property: RunProperty::new(),
315 style: None,
316 numbering_property: None,
317 alignment: None,
318 indent: None,
319 line_spacing: None,
320 ..Default::default()
321 },
322 has_numbering: false,
323 }
324 );
325 }
326
327 #[test]
328 fn test_read_bookmark() {
329 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
330 <w:p>
331 <w:bookmarkStart w:id="0" w:name="ABCD-1234"/>
332 <w:r>
333 <w:rPr></w:rPr>
334 <w:t>Bookmarked</w:t>
335 </w:r>
336 <w:bookmarkEnd w:id="0"/>
337 </w:p>
338</w:document>"#;
339 let mut parser = EventReader::new(c.as_bytes());
340 let p = Paragraph::read(&mut parser, &[]).unwrap();
341
342 assert_eq!(
343 p,
344 Paragraph {
345 id: "12345678".to_owned(),
346 children: vec![
347 ParagraphChild::BookmarkStart(BookmarkStart::new(0, "ABCD-1234")),
348 ParagraphChild::Run(Box::new(Run::new().add_text("Bookmarked"))),
349 ParagraphChild::BookmarkEnd(BookmarkEnd::new(0)),
350 ],
351 property: ParagraphProperty {
352 run_property: RunProperty::new(),
353 style: None,
354 numbering_property: None,
355 alignment: None,
356 indent: None,
357 line_spacing: None,
358 ..Default::default()
359 },
360 has_numbering: false,
361 }
362 );
363 }
364
365 #[test]
366 fn test_read_two_insert() {
367 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
368 <w:p>
369 <w:ins w:id="0" w:author="unknown" w:date="2019-11-15T14:19:04Z">
370 <w:r>
371 <w:rPr></w:rPr>
372 <w:t>W</w:t>
373 </w:r>
374 </w:ins>
375 <w:ins w:id="0" w:author="unknown" w:date="2019-11-15T14:19:04Z">
376 <w:r>
377 <w:rPr></w:rPr>
378 <w:t>H</w:t>
379 </w:r>
380 </w:ins>
381 </w:p>
382</w:document>"#;
383 let mut parser = EventReader::new(c.as_bytes());
384 let p = Paragraph::read(&mut parser, &[]).unwrap();
385 assert_eq!(
386 p,
387 Paragraph {
388 id: "12345678".to_owned(),
389 children: vec![
390 ParagraphChild::Insert(
391 Insert::new(Run::new().add_text("W"))
392 .author("unknown")
393 .date("2019-11-15T14:19:04Z")
394 ),
395 ParagraphChild::Insert(
396 Insert::new(Run::new().add_text("H"))
397 .author("unknown")
398 .date("2019-11-15T14:19:04Z")
399 )
400 ],
401 property: ParagraphProperty {
402 run_property: RunProperty::new(),
403 style: None,
404 numbering_property: None,
405 alignment: None,
406 indent: None,
407 line_spacing: None,
408 ..Default::default()
409 },
410 has_numbering: false,
411 }
412 );
413 }
414
415 #[test]
416 fn test_read_two_run_in_insert() {
417 let c = r#"<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
418 <w:p>
419 <w:ins w:id="0" w:author="unknown" w:date="2019-11-15T14:19:04Z">
420 <w:r>
421 <w:rPr></w:rPr>
422 <w:t>W</w:t>
423 </w:r>
424 <w:r>
425 <w:rPr></w:rPr>
426 <w:t>H</w:t>
427 </w:r>
428 </w:ins>
429 </w:p>
430</w:document>"#;
431 let mut parser = EventReader::new(c.as_bytes());
432 let p = Paragraph::read(&mut parser, &[]).unwrap();
433 assert_eq!(
434 p,
435 Paragraph {
436 id: "12345678".to_owned(),
437 children: vec![ParagraphChild::Insert(
438 Insert::new(Run::new().add_text("W"))
439 .author("unknown")
440 .date("2019-11-15T14:19:04Z")
441 .add_run(Run::new().add_text("H")),
442 )],
443 property: ParagraphProperty {
444 run_property: RunProperty::new(),
445 style: None,
446 numbering_property: None,
447 alignment: None,
448 indent: None,
449 line_spacing: None,
450 ..Default::default()
451 },
452 has_numbering: false,
453 }
454 );
455 }
456}