Skip to main content

embedded_xml/
attributes.rs

1/// XML attribute reader
2#[derive(Clone)]
3pub struct AttributeReader<'a> {
4    split: core::str::SplitAsciiWhitespace<'a>,
5}
6
7impl core::fmt::Debug for AttributeReader<'_> {
8    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
9        let mut builder = f.debug_map();
10        for (n, v) in self.clone() {
11            builder.entry(&n, &v);
12        }
13        builder.finish()
14    }
15}
16
17impl Default for AttributeReader<'_> {
18    fn default() -> Self {
19        AttributeReader {
20            split: "".split_ascii_whitespace(),
21        }
22    }
23}
24
25impl PartialEq for AttributeReader<'_> {
26    fn eq(&self, other: &Self) -> bool {
27        self.clone()
28            .zip(other.clone())
29            .all(|((n1, v1), (n2, v2))| n1.eq_ignore_ascii_case(n2) && v1 == v2)
30    }
31}
32
33impl<'a> AttributeReader<'a> {
34    /// ```
35    /// # use embedded_xml::AttributeReader;
36    /// let mut reader = AttributeReader::from_block(r#"foo="bar" baz='qux'"#);
37    /// assert_eq!(reader.next(), Some(("foo", "bar")));
38    /// assert_eq!(reader.next(), Some(("baz", "qux")));
39    /// assert_eq!(reader.next(), None);
40    /// ```
41    pub fn from_block(buffer: &str) -> AttributeReader<'_> {
42        AttributeReader {
43            split: buffer.trim_ascii().split_ascii_whitespace(),
44        }
45    }
46
47    /// ```
48    /// # use embedded_xml::AttributeReader;
49    /// let mut split = r#"item foo="bar" baz='qux'"#.split_ascii_whitespace();
50    /// let name = split.next().unwrap();
51    /// assert_eq!(name, "item");
52    /// let mut reader = AttributeReader::from_split(split);
53    /// assert_eq!(reader.next(), Some(("foo", "bar")));
54    /// assert_eq!(reader.next(), Some(("baz", "qux")));
55    /// assert_eq!(reader.next(), None);
56    /// ```
57    pub fn from_split(split: core::str::SplitAsciiWhitespace<'_>) -> AttributeReader<'_> {
58        AttributeReader { split }
59    }
60
61    /// Case-insensitive search by attribute name. Returns the value or None.
62    /// ```
63    /// # use embedded_xml::AttributeReader;
64    /// let reader = AttributeReader::from_block(r#"foo="bar" baz='qux'"#);
65    /// assert_eq!(reader.get("foo"), Some("bar"));
66    /// assert_eq!(reader.get("baz"), Some("qux"));
67    /// assert_eq!(reader.get("nonexistent"), None);
68    /// assert_eq!(reader.get("foo"), Some("bar"));
69    /// ```
70    pub fn get(&self, name: &str) -> Option<&str> {
71        for (n, v) in self.clone() {
72            if n.eq_ignore_ascii_case(name) {
73                return Some(v);
74            }
75        }
76        None
77    }
78}
79
80impl<'a> Iterator for AttributeReader<'a> {
81    type Item = (&'a str, &'a str);
82
83    fn next(&mut self) -> Option<Self::Item> {
84        let part = self.split.next()?;
85        let mut iter = part.splitn(2, '=');
86        let name = iter.next()?;
87        let value = iter.next()?.trim_matches('"').trim_matches('\'');
88        Some((name, value))
89    }
90}