use std::io::Read; use std::str::FromStr; use xml::attribute::OwnedAttribute; use xml::reader::{EventReader, XmlEvent}; use super::*; use super::attributes::*; use crate::types::*; impl ElementReader for Paragraph { fn read( r: &mut EventReader, attrs: &[OwnedAttribute], ) -> Result { let mut p = Paragraph::new(); loop { let e = r.next(); match e { Ok(XmlEvent::StartElement { attributes, name, .. }) => { let e = XMLElement::from_str(&name.local_name).unwrap(); match e { XMLElement::Run => { let run = Run::read(r, attrs)?; p = p.add_run(run); continue; } XMLElement::Insert => { let ins = Insert::read(r, &attributes)?; p = p.add_insert(ins); continue; } XMLElement::Delete => { let del = Delete::read(r, &attributes)?; p = p.add_delete(del); continue; } XMLElement::BookmarkStart => { let mut id: Option = None; let mut name: Option = None; for a in attributes { let local_name = &a.name.local_name; if local_name == "id" { id = Some(usize::from_str(&a.value)?); } else if local_name == "name" { name = Some(a.value.clone()); } } if id.is_none() || name.is_none() { return Err(ReaderError::XMLReadError); } p = p.add_bookmark_start(id.unwrap(), name.unwrap()); continue; } XMLElement::BookmarkEnd => { let mut id: Option = None; for a in attributes { let local_name = &a.name.local_name; if local_name == "id" { id = Some(usize::from_str(&a.value)?); } } if let Some(id) = id { p = p.add_bookmark_end(id); } else { return Err(ReaderError::XMLReadError); } continue; } XMLElement::CommentRangeStart => { // TODO: Support comment later. continue; } XMLElement::CommentRangeEnd => { p = p.add_comment_end(usize::from_str(&attributes[0].value)?); continue; } XMLElement::Indent => { let (start, end, special, start_chars) = read_indent(&attributes)?; p = p.indent(start, special, end, start_chars); continue; } XMLElement::Justification => { p = p.align(AlignmentType::from_str(&attributes[0].value)?); continue; } XMLElement::ParagraphStyle => { p = p.style(&attributes[0].value); continue; } XMLElement::NumberingProperty => { let num_pr = NumberingProperty::read(r, attrs)?; if num_pr.id.is_some() && num_pr.level.is_some() { p = p.numbering(num_pr.id.unwrap(), num_pr.level.unwrap()); } continue; } _ => {} } } Ok(XmlEvent::EndElement { name, .. }) => { let e = XMLElement::from_str(&name.local_name).unwrap(); if e == XMLElement::Paragraph { return Ok(p); } } Err(_) => return Err(ReaderError::XMLReadError), _ => {} } } } } #[cfg(test)] mod tests { use super::*; #[cfg(test)] use pretty_assertions::assert_eq; #[test] fn test_read_indent() { let c = r#" a "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![ParagraphChild::Run(Run::new().add_text("a"))], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: None, alignment: None, indent: Some(Indent::new( Some(1470), Some(SpecialIndentType::Hanging(0)), Some(1270), None, )), }, has_numbering: false, attrs: Vec::new(), } ); } #[test] fn test_read_indent_start_chars() { let c = r#" a "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![ParagraphChild::Run(Run::new().add_text("a"))], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: None, alignment: None, indent: Some(Indent::new(None, None, None, Some(100))), }, has_numbering: false, attrs: Vec::new(), } ); } #[test] fn test_read_jc() { let c = r#" "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: None, alignment: Some(Justification::new(AlignmentType::Left.to_string())), indent: None, }, has_numbering: false, attrs: vec![], } ); } #[test] fn test_read_numbering() { let c = r#" "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: Some( NumberingProperty::new().add_num(NumberingId::new(1), IndentLevel::new(0),) ), alignment: None, indent: None, }, has_numbering: true, attrs: vec![], } ); } #[test] fn test_read_insert() { let c = r#" W "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![ParagraphChild::Insert( Insert::new(Run::new().add_text("W")) .author("unknown") .date("2019-11-15T14:19:04Z") )], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: None, alignment: None, indent: None, }, has_numbering: false, attrs: vec![], } ); } #[test] fn test_read_delete() { let c = r#" Hello "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![ParagraphChild::Delete( Delete::new(Run::new().add_delete_text("Hello ")) .author("unknown") .date("2019-11-15T14:19:04Z") )], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: None, alignment: None, indent: None, }, has_numbering: false, attrs: vec![], } ); } #[test] fn test_read_bookmark() { let c = r#" Bookmarked "#; let mut parser = EventReader::new(c.as_bytes()); let p = Paragraph::read(&mut parser, &[]).unwrap(); assert_eq!( p, Paragraph { children: vec![ ParagraphChild::BookmarkStart(BookmarkStart::new(0, "ABCD-1234")), ParagraphChild::Run(Run::new().add_text("Bookmarked")), ParagraphChild::BookmarkEnd(BookmarkEnd::new(0)), ], property: ParagraphProperty { run_property: RunProperty::new(), style: None, numbering_property: None, alignment: None, indent: None, }, has_numbering: false, attrs: vec![], } ); } }