1use std;
16use std::error::Error;
17use std::io::Write;
18use std::rc::Rc;
19
20use super::traits::{ConvertResult, Converter};
21use crate::build::Val;
22use crate::error::BuildError;
23use crate::error::ErrorType;
24
25use xml::common::XmlVersion;
26use xml::writer::events::XmlEvent;
27use xml::writer::EventWriter;
28use xml::EmitterConfig;
29
30pub struct XmlConverter {}
31
32impl XmlConverter {
33 fn get_str_val(v: &Val) -> std::result::Result<&str, Box<dyn Error>> {
34 if let Val::Str(ref s) = v {
35 Ok(s)
36 } else {
37 Err(BuildError::new("Not a String value", ErrorType::TypeFail).to_boxed())
38 }
39 }
40
41 fn get_tuple_val(v: &Val) -> std::result::Result<&Vec<(String, Rc<Val>)>, Box<dyn Error>> {
42 if let Val::Tuple(ref fs) = v {
43 Ok(fs)
44 } else {
45 Err(BuildError::new("Not a tuple value", ErrorType::TypeFail).to_boxed())
46 }
47 }
48
49 fn get_list_val(v: &Val) -> std::result::Result<&Vec<Rc<Val>>, Box<dyn Error>> {
50 if let Val::List(ref fs) = v {
51 Ok(fs)
52 } else {
53 Err(BuildError::new("Not a List value", ErrorType::TypeFail).to_boxed())
54 }
55 }
56
57 fn write_node<W: std::io::Write>(&self, v: &Val, w: &mut EventWriter<W>) -> ConvertResult {
58 if let Val::Tuple(ref fs) = v {
60 let mut name: Option<&str> = None;
61 let mut attrs: Option<&Vec<(String, Rc<Val>)>> = None;
62 let mut children: Option<&Vec<Rc<Val>>> = None;
63 let mut text: Option<&str> = None;
64 let mut ns: Option<(&str, &str)> = None;
65 for (ref field, ref val) in fs.iter() {
66 if field == "name" {
67 name = Some(Self::get_str_val(val.as_ref())?);
68 }
69 if field == "ns" {
70 if let Val::Tuple(ref fs) = val.as_ref() {
71 let mut prefix = "";
72 let mut uri = "";
73 for (ref name, ref val) in fs.iter() {
74 if val.is_empty() {
75 continue;
76 }
77 if name == "uri" {
78 uri = Self::get_str_val(val.as_ref())?;
79 }
80 if name == "prefix" {
81 prefix = Self::get_str_val(val.as_ref())?;
82 }
83 }
84 if uri != "" && prefix != "" {
85 ns = Some((prefix, uri));
86 }
87 } else if let Val::Str(ref s) = val.as_ref() {
88 ns = Some(("", s));
89 }
90 }
91 if field == "attrs" {
92 if !val.is_empty() {
94 attrs = Some(Self::get_tuple_val(val.as_ref())?);
95 }
96 }
97 if field == "children" {
98 if !val.is_empty() {
100 children = Some(Self::get_list_val(val.as_ref())?);
101 }
102 }
103 if field == "text" {
104 if !val.is_empty() {
105 text = Some(Self::get_str_val(val.as_ref())?);
106 }
107 }
108 }
109 if name.is_some() && text.is_some() {
110 return Err(BuildError::new(
111 "XML nodes can not have both text and name fields",
112 ErrorType::TypeFail,
113 )
114 .to_boxed());
115 }
116 if name.is_some() {
117 let mut start = XmlEvent::start_element(name.unwrap());
118 if attrs.is_some() {
119 for (ref name, ref val) in attrs.unwrap().iter() {
120 if val.is_empty() {
121 continue;
122 }
123 start = start.attr(name.as_ref(), Self::get_str_val(val.as_ref())?);
124 }
125 }
126 if let Some((prefix, uri)) = ns {
127 if prefix == "" {
128 start = start.default_ns(uri);
129 } else {
130 start = start.ns(prefix, uri);
131 }
132 }
133 w.write(start)?;
134 if children.is_some() {
135 for child in children.unwrap().iter() {
136 self.write_node(child.as_ref(), w)?;
137 }
138 }
139 w.write(XmlEvent::end_element())?;
140 }
141 if text.is_some() {
142 w.write(XmlEvent::characters(text.unwrap()))?;
143 }
144 } else if let Val::Str(ref s) = v {
145 w.write(XmlEvent::characters(s.as_ref()))?;
146 } else {
147 return Err(BuildError::new(
148 "XML nodes must be a Tuple or a string",
149 ErrorType::TypeFail,
150 )
151 .to_boxed());
152 }
153 Ok(())
154 }
155
156 fn write(&self, v: &Val, w: &mut dyn Write) -> ConvertResult {
157 if let Val::Tuple(ref fs) = v {
158 let mut version: Option<&str> = None;
159 let mut encoding: Option<&str> = None;
160 let mut standalone: Option<bool> = None;
161 let mut root: Option<Rc<Val>> = None;
162 for &(ref name, ref val) in fs.iter() {
163 if name == "version" {
164 version = Some(Self::get_str_val(val)?);
165 }
166 if name == "encoding" {
167 encoding = Some(Self::get_str_val(val)?);
168 }
169 if name == "standalone" {
170 standalone = match val.as_ref() {
171 Val::Boolean(b) => Some(*b),
172 _ => None,
173 };
174 }
175 if name == "root" {
176 root = Some(val.clone());
177 }
178 }
179 match root {
180 Some(n) => {
181 let mut writer = EmitterConfig::new()
182 .perform_indent(true)
183 .normalize_empty_elements(false)
184 .create_writer(w);
185 let version = match version {
188 Some(s) => {
189 if s == "1.0" {
190 Some(XmlVersion::Version10)
191 } else if s == "1.1" {
192 Some(XmlVersion::Version11)
193 } else {
194 return Err(BuildError::new(
197 "XML version must be either 1.0 or 1.1",
198 ErrorType::TypeFail,
199 )
200 .to_boxed());
201 }
202 }
203 None => None,
204 };
205 writer.write(XmlEvent::StartDocument {
206 version: version.unwrap_or(XmlVersion::Version10),
208 encoding: encoding,
209 standalone: standalone,
210 })?;
211 self.write_node(n.as_ref(), &mut writer)
212 }
213 None => Err(BuildError::new(
214 "XML doc tuples must have a root field",
215 ErrorType::TypeFail,
216 )
217 .to_boxed()),
218 }
219 } else {
220 Err(BuildError::new("XML outputs must be a Tuple", ErrorType::TypeFail).to_boxed())
221 }
222 }
223}
224
225impl Converter for XmlConverter {
226 fn convert(&self, v: Rc<Val>, mut w: &mut dyn Write) -> ConvertResult {
227 self.write(&v, &mut w)
228 }
229
230 fn file_ext(&self) -> String {
231 String::from("xml")
232 }
233
234 fn description(&self) -> String {
235 String::from("Convert a ucg DSL into xml.")
236 }
237
238 #[allow(unused_must_use)]
239 fn help(&self) -> String {
240 include_str!("xml_help.txt").to_string()
241 }
242}