cim/xml_tags/
xml_rs.rs

1use super::types::Tag;
2use super::types::TagError;
3use super::types::TagEvent;
4use super::types::TagParser;
5
6use std::collections::HashMap;
7use std::error::Error;
8use std::fs::File;
9use std::io::{BufReader, Read};
10use xml::attribute::OwnedAttribute;
11use xml::reader::{EventReader, Events, XmlEvent};
12
13pub struct XmlTagParser {
14  tag_parser: Events<BufReader<Box<dyn Read>>>,
15}
16
17impl Iterator for XmlTagParser {
18  type Item = Result<TagEvent, TagError>;
19
20  fn next(&mut self) -> Option<Result<TagEvent, TagError>> {
21    loop {
22      match self.tag_parser.next() {
23        Some(Ok(XmlEvent::StartElement {
24          name, attributes, ..
25        }))
26          if Self::is_supported_tag(&name.local_name) =>
27        {
28          return Some(Ok(Self::build_open_tag_event(name.local_name, &attributes)))
29        }
30        Some(Ok(XmlEvent::EndElement { name })) if Self::is_supported_tag(&name.local_name) => {
31          return Some(Ok(Self::build_close_tag_event(name.local_name)))
32        }
33        Some(Err(e)) => return Some(Err(TagError::new(e.msg()))),
34        None => return None,
35        _ => continue,
36      }
37    }
38  }
39}
40
41impl TagParser for XmlTagParser {}
42
43impl XmlTagParser {
44  pub fn new(reader: Box<dyn Read>) -> Self {
45    let file = BufReader::new(reader);
46    let tag_parser = EventReader::new(file);
47    let tag_parser = tag_parser.into_iter();
48    XmlTagParser { tag_parser }
49  }
50
51  pub fn from_file(path: String) -> Result<Self, Box<dyn Error>> {
52    let file = Box::new(File::open(path)?) as Box<dyn Read>;
53    Ok(Self::new(file))
54  }
55
56  fn build_open_tag_event(name: String, attributes: &[OwnedAttribute]) -> TagEvent {
57    let tag = Self::build_tag(name);
58    let attributes = Self::parse_attributes(attributes);
59    TagEvent::Open { tag, attributes }
60  }
61
62  fn parse_attributes(attributes: &[OwnedAttribute]) -> HashMap<String, String> {
63    let mut attributes_map = HashMap::new();
64    for attribute in attributes.iter() {
65      let key = attribute.name.local_name.clone();
66      let value = attribute.value.clone();
67      attributes_map.insert(key, value);
68    }
69    attributes_map
70  }
71
72  fn build_close_tag_event(name: String) -> TagEvent {
73    let tag = Self::build_tag(name);
74    TagEvent::Close { tag }
75  }
76
77  fn build_tag(name: String) -> Tag {
78    match name.as_str() {
79      "Schema" => Tag::Schema,
80      "EntityType" => Tag::EntityType,
81      "Property" => Tag::Property,
82      "NavigationProperty" => Tag::NavigationProperty,
83      _ => Tag::PropertyRef,
84    }
85  }
86
87  fn is_supported_tag(name: &str) -> bool {
88    name == "Schema"
89      || name == "EntityType"
90      || name == "Property"
91      || name == "PropertyRef"
92      || name == "NavigationProperty"
93  }
94}