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