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}