1 // This file is part of rss.
2 //
3 // Copyright © 2015-2021 The rust-syndication Developers
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the MIT License and/or Apache 2.0 License.
7 
8 use std::collections::BTreeMap;
9 use std::io::BufRead;
10 use std::str;
11 
12 use quick_xml::events::attributes::Attributes;
13 use quick_xml::events::Event;
14 use quick_xml::Reader;
15 
16 use crate::error::Error;
17 use crate::extension::{Extension, ExtensionMap};
18 
extension_name(element_name: &[u8]) -> Option<(&[u8], &[u8])>19 pub fn extension_name(element_name: &[u8]) -> Option<(&[u8], &[u8])> {
20     let mut split = element_name.splitn(2, |b| *b == b':');
21     match split.next() {
22         Some(b"") | None => None,
23         Some(ns) => split.next().map(|name| (ns, name)),
24     }
25 }
26 
parse_extension<R>( reader: &mut Reader<R>, atts: Attributes, ns: &[u8], name: &[u8], extensions: &mut ExtensionMap, ) -> Result<(), Error> where R: BufRead,27 pub fn parse_extension<R>(
28     reader: &mut Reader<R>,
29     atts: Attributes,
30     ns: &[u8],
31     name: &[u8],
32     extensions: &mut ExtensionMap,
33 ) -> Result<(), Error>
34 where
35     R: BufRead,
36 {
37     let ns = str::from_utf8(ns)?;
38     let name = str::from_utf8(name)?;
39     let ext = parse_extension_element(reader, atts)?;
40 
41     let map = extensions
42         .entry(ns.to_string())
43         .or_insert_with(BTreeMap::new);
44 
45     let items = map.entry(name.to_string()).or_insert_with(Vec::new);
46     items.push(ext);
47 
48     Ok(())
49 }
50 
parse_extension_element<R: BufRead>( reader: &mut Reader<R>, mut atts: Attributes, ) -> Result<Extension, Error>51 fn parse_extension_element<R: BufRead>(
52     reader: &mut Reader<R>,
53     mut atts: Attributes,
54 ) -> Result<Extension, Error> {
55     let mut extension = Extension::default();
56     let mut buf = Vec::new();
57 
58     for attr in atts.with_checks(false).flatten() {
59         let key = str::from_utf8(attr.key)?;
60         let value = attr.unescape_and_decode_value(reader)?;
61         extension.attrs.insert(key.to_string(), value);
62     }
63 
64     loop {
65         match reader.read_event(&mut buf)? {
66             Event::Start(element) => {
67                 let ext = parse_extension_element(reader, element.attributes())?;
68                 let name = str::from_utf8(element.local_name())?;
69                 let items = extension
70                     .children
71                     .entry(name.to_string())
72                     .or_insert_with(Vec::new);
73 
74                 items.push(ext);
75             }
76             Event::Text(element) | Event::CData(element) => {
77                 extension.value = Some(element.unescape_and_decode(reader)?);
78             }
79             Event::End(element) => {
80                 extension.name = reader.decode(element.name()).into();
81                 break;
82             }
83             Event::Eof => return Err(Error::Eof),
84             _ => {}
85         }
86 
87         buf.clear();
88     }
89 
90     Ok(extension)
91 }
92 
get_extension_values(v: Vec<Extension>) -> Vec<String>93 pub fn get_extension_values(v: Vec<Extension>) -> Vec<String> {
94     v.into_iter()
95         .filter_map(|ext| ext.value)
96         .collect::<Vec<_>>()
97 }
98 
remove_extension_value( map: &mut BTreeMap<String, Vec<Extension>>, key: &str, ) -> Option<String>99 pub fn remove_extension_value(
100     map: &mut BTreeMap<String, Vec<Extension>>,
101     key: &str,
102 ) -> Option<String> {
103     map.remove(key)
104         .map(|mut v| v.remove(0))
105         .and_then(|ext| ext.value)
106 }
107