|
1 | 1 | use crate::errors::TraversingError;
|
2 |
| -use xml::Element; |
3 |
| -use xml::Xml::{CharacterNode, ElementNode}; |
4 | 2 |
|
5 | 3 | pub trait FromStringOptional<T> {
|
6 | 4 | fn from_str_optional(s: &str) -> Result<T, TraversingError>;
|
@@ -101,280 +99,9 @@ pub fn from_azure_time(s: &str) -> Result<chrono::DateTime<chrono::Utc>, chrono:
|
101 | 99 | }
|
102 | 100 | }
|
103 | 101 |
|
104 |
| -#[inline] |
105 |
| -pub fn traverse_single_must<'a>( |
106 |
| - node: &'a Element, |
107 |
| - path: &[&str], |
108 |
| -) -> Result<&'a Element, TraversingError> { |
109 |
| - let vec = traverse(node, path, false)?; |
110 |
| - if vec.len() > 1 { |
111 |
| - return Err(TraversingError::MultipleNode( |
112 |
| - path[path.len() - 1].to_owned(), |
113 |
| - )); |
114 |
| - } |
115 |
| - |
116 |
| - Ok(vec[0]) |
117 |
| -} |
118 |
| - |
119 |
| -pub fn traverse_single_optional<'a>( |
120 |
| - node: &'a Element, |
121 |
| - path: &[&str], |
122 |
| -) -> Result<Option<&'a Element>, TraversingError> { |
123 |
| - let vec = traverse(node, path, true)?; |
124 |
| - if vec.len() > 1 { |
125 |
| - return Err(TraversingError::MultipleNode( |
126 |
| - path[path.len() - 1].to_owned(), |
127 |
| - )); |
128 |
| - } |
129 |
| - |
130 |
| - if vec.is_empty() { |
131 |
| - return Ok(None); |
132 |
| - } |
133 |
| - |
134 |
| - Ok(Some(vec[0])) |
135 |
| -} |
136 |
| - |
137 |
| -#[inline] |
138 |
| -pub fn traverse<'a>( |
139 |
| - node: &'a Element, |
140 |
| - path: &[&str], |
141 |
| - ignore_empty_leaf: bool, |
142 |
| -) -> Result<Vec<&'a Element>, TraversingError> { |
143 |
| - trace!( |
144 |
| - "traverse(node == {:?}, path == {:?}, ignore_empty_leaf == {})", |
145 |
| - node, |
146 |
| - path, |
147 |
| - ignore_empty_leaf |
148 |
| - ); |
149 |
| - // debug!("path.len() == {:?}", path.len()); |
150 |
| - |
151 |
| - if path.is_empty() { |
152 |
| - return Ok(vec![node]); |
153 |
| - } |
154 |
| - |
155 |
| - let mut curnode = node; |
156 |
| - |
157 |
| - for (x, item) in path.iter().enumerate() { |
158 |
| - // debug!("x == {}, path[x] == {}", x, path[x]); |
159 |
| - |
160 |
| - let vec = find_subnodes(curnode, item); |
161 |
| - if vec.is_empty() { |
162 |
| - if (x + 1) >= path.len() && ignore_empty_leaf { |
163 |
| - return Ok(vec); |
164 |
| - } else { |
165 |
| - return Err(TraversingError::PathNotFound((*item).to_owned())); |
166 |
| - } |
167 |
| - } |
168 |
| - |
169 |
| - if vec.len() > 1 && (x + 1) < path.len() { |
170 |
| - return Err(TraversingError::MultipleNode((*item).to_owned())); |
171 |
| - } |
172 |
| - |
173 |
| - if (x + 1) >= path.len() { |
174 |
| - return Ok(vec); |
175 |
| - } |
176 |
| - |
177 |
| - curnode = vec[0]; |
178 |
| - } |
179 |
| - |
180 |
| - unreachable!(); |
181 |
| -} |
182 |
| - |
183 |
| -#[inline] |
184 |
| -pub fn find_subnodes<'a>(node: &'a Element, subnode: &str) -> Vec<&'a Element> { |
185 |
| - node.children |
186 |
| - .iter() |
187 |
| - .filter(|x| match **x { |
188 |
| - ElementNode(ref mynode) => mynode.name == subnode, |
189 |
| - _ => false, |
190 |
| - }) |
191 |
| - .map(|x| match *x { |
192 |
| - ElementNode(ref mynode) => mynode, |
193 |
| - _ => unreachable!(), |
194 |
| - }) |
195 |
| - .collect::<Vec<_>>() |
196 |
| -} |
197 |
| - |
198 |
| -#[inline] |
199 |
| -pub fn inner_text(node: &Element) -> Result<&str, TraversingError> { |
200 |
| - for child in &node.children { |
201 |
| - match *child { |
202 |
| - CharacterNode(ref txt) => return Ok(txt), |
203 |
| - _ => continue, |
204 |
| - }; |
205 |
| - } |
206 |
| - |
207 |
| - Ok("") |
208 |
| - |
209 |
| - //debug!("\n!!! node == {}", node); |
210 |
| - //Err(TraversingError::TextNotFound) |
211 |
| -} |
212 |
| - |
213 |
| -#[inline] |
214 |
| -pub fn cast_optional<'a, T>(node: &'a Element, path: &[&str]) -> Result<Option<T>, TraversingError> |
215 |
| -where |
216 |
| - T: FromStringOptional<T>, |
217 |
| -{ |
218 |
| - match traverse_single_optional(node, path)? { |
219 |
| - Some(e) => match inner_text(e) { |
220 |
| - Ok(txt) => Ok(Some(T::from_str_optional(txt)?)), |
221 |
| - Err(_) => Ok(None), |
222 |
| - }, |
223 |
| - None => Ok(None), |
224 |
| - } |
225 |
| -} |
226 |
| - |
227 |
| -#[inline] |
228 |
| -pub fn cast_must<'a, T>(node: &'a Element, path: &[&str]) -> Result<T, TraversingError> |
229 |
| -where |
230 |
| - T: FromStringOptional<T>, |
231 |
| -{ |
232 |
| - let node = traverse_single_must(node, path)?; |
233 |
| - let itxt = inner_text(node)?; |
234 |
| - T::from_str_optional(itxt) |
235 |
| -} |
236 |
| - |
237 | 102 | #[cfg(test)]
|
238 | 103 | mod test {
|
239 | 104 | use chrono::{Datelike, Timelike};
|
240 |
| - use xml::Element; |
241 |
| - |
242 |
| - const XML: &'static str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> |
243 |
| -<EnumerationResults \ |
244 |
| - ServiceEndpoint=\"http://mindrust.blob.core.windows.net/\"> |
245 |
| - \ |
246 |
| - <Containers> |
247 |
| - <Container> |
248 |
| - <Name>pippo</Name> |
249 |
| - \ |
250 |
| - <Properties> |
251 |
| - <Last-Modified>Mon, 23Nov 2015 21:12:35 \ |
252 |
| - GMT</Last-Modified> |
253 |
| - <Etag>\"0x8D2F44ACF757699\"</Etag> |
254 |
| - \ |
255 |
| - <LeaseStatus>unlocked</LeaseStatus> |
256 |
| - \ |
257 |
| - <LeaseState>available</LeaseState> |
258 |
| - \ |
259 |
| - <SomeNumber>256</SomeNumber> |
260 |
| - </Properties> |
261 |
| - </Container> |
262 |
| - \ |
263 |
| - <Container> |
264 |
| - <Name>pluto</Name> |
265 |
| - <Properties> |
266 |
| - \ |
267 |
| - <Last-Modified>Mon, 23Nov 2015 21:12:35 GMT</Last-Modified> |
268 |
| - \ |
269 |
| - <Etag>\"0xAA2F44ACF757699\"</Etag> |
270 |
| - \ |
271 |
| - <LeaseStatus>locked</LeaseStatus> |
272 |
| - \ |
273 |
| - <LeaseState>available</LeaseState> |
274 |
| - </Properties> |
275 |
| - \ |
276 |
| - </Container> |
277 |
| - </Containers> |
278 |
| - <NextMarker /> |
279 |
| -</EnumerationResults>"; |
280 |
| - |
281 |
| - #[test] |
282 |
| - fn test_cast_optional_1() { |
283 |
| - let elem: Element = XML.parse().unwrap(); |
284 |
| - |
285 |
| - let sub1 = super::traverse(&elem, &["Containers", "Container"], false).unwrap(); |
286 |
| - |
287 |
| - { |
288 |
| - let num = super::cast_optional::<u64>(sub1[0], &["Properties", "SomeNumber"]).unwrap(); |
289 |
| - assert_eq!(Some(256u64), num); |
290 |
| - } |
291 |
| - |
292 |
| - { |
293 |
| - let num2 = super::cast_optional::<u64>(sub1[1], &["Properties", "SomeNumber"]).unwrap(); |
294 |
| - assert_eq!(None, num2); |
295 |
| - } |
296 |
| - } |
297 |
| - |
298 |
| - #[test] |
299 |
| - fn test_first_1() { |
300 |
| - let elem: Element = XML.parse().unwrap(); |
301 |
| - |
302 |
| - let sub1 = super::find_subnodes(&elem, "Containers"); |
303 |
| - assert_eq!(1, sub1.len()); |
304 |
| - |
305 |
| - let sub2 = super::find_subnodes(&sub1[0], "Container"); |
306 |
| - assert_eq!(2, sub2.len()); |
307 |
| - } |
308 |
| - |
309 |
| - #[test] |
310 |
| - fn test_inner_2() { |
311 |
| - let elem: Element = XML.parse().unwrap(); |
312 |
| - |
313 |
| - let mut sub = super::find_subnodes(&elem, "Containers"); |
314 |
| - sub = super::find_subnodes(&sub[0], "Container"); |
315 |
| - sub = super::find_subnodes(&sub[0], "Properties"); |
316 |
| - sub = super::find_subnodes(&sub[0], "LeaseStatus"); |
317 |
| - |
318 |
| - if let Ok(inner) = super::inner_text(&sub[0]) { |
319 |
| - assert_eq!(inner, "unlocked"); |
320 |
| - } else { |
321 |
| - panic!("should have found CharacterNode"); |
322 |
| - } |
323 |
| - } |
324 |
| - |
325 |
| - #[test] |
326 |
| - fn test_traverse_1() { |
327 |
| - let elem: Element = XML.parse().unwrap(); |
328 |
| - |
329 |
| - let mut res = super::traverse(&elem, &["Containers", "Container"], false).unwrap(); |
330 |
| - res = super::traverse(res[0], &["Properties", "LeaseStatus"], false).unwrap(); |
331 |
| - |
332 |
| - if let Ok(inner) = super::inner_text(&res[0]) { |
333 |
| - assert_eq!(inner, "unlocked"); |
334 |
| - } else { |
335 |
| - panic!("should have found CharacterNode"); |
336 |
| - } |
337 |
| - } |
338 |
| - |
339 |
| - #[test] |
340 |
| - fn test_traverse_2() { |
341 |
| - let elem: Element = XML.parse().unwrap(); |
342 |
| - |
343 |
| - let mut res = super::traverse(&elem, &["Containers", "Container"], false).unwrap(); |
344 |
| - res = super::traverse(res[1], &["Properties", "LeaseStatus"], false).unwrap(); |
345 |
| - |
346 |
| - if let Ok(inner) = super::inner_text(&res[0]) { |
347 |
| - assert_eq!(inner, "locked"); |
348 |
| - } else { |
349 |
| - panic!("should have found CharacterNode"); |
350 |
| - } |
351 |
| - } |
352 |
| - |
353 |
| - #[test] |
354 |
| - fn test_traverse_single_must_1() { |
355 |
| - let elem: Element = XML.parse().unwrap(); |
356 |
| - |
357 |
| - let res = super::traverse(&elem, &["Containers", "Container"], false).unwrap(); |
358 |
| - let res_final = |
359 |
| - super::traverse_single_must(res[1], &["Properties", "LeaseStatus"]).unwrap(); |
360 |
| - |
361 |
| - if let Ok(inner) = super::inner_text(res_final) { |
362 |
| - assert_eq!(inner, "locked"); |
363 |
| - } else { |
364 |
| - panic!("should have found CharacterNode"); |
365 |
| - } |
366 |
| - } |
367 |
| - |
368 |
| - #[test] |
369 |
| - fn test_traverse_single_optional_1() { |
370 |
| - let elem: Element = XML.parse().unwrap(); |
371 |
| - |
372 |
| - let res = super::traverse(&elem, &["Containers", "Container"], false).unwrap(); |
373 |
| - let res_final = |
374 |
| - super::traverse_single_optional(res[1], &["Properties", "Pinocchio"]).unwrap(); |
375 |
| - |
376 |
| - assert_eq!(res_final, None); |
377 |
| - } |
378 | 105 |
|
379 | 106 | #[test]
|
380 | 107 | fn test_from_azure_time() {
|
|
0 commit comments