1//! Contains XML attributes manipulation types and functions.
2
3use std::fmt;
4
5use crate::escape::{AttributeEscapes, Escaped};
6use crate::name::{Name, OwnedName};
7
8/// A borrowed version of an XML attribute.
9///
10/// Consists of a borrowed qualified name and a borrowed string value.
11#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
12pub struct Attribute<'a> {
13 /// Attribute name.
14 pub name: Name<'a>,
15
16 /// Attribute value.
17 pub value: &'a str,
18}
19
20impl fmt::Display for Attribute<'_> {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 write!(f, "{}=\"{}\"", self.name, Escaped::<AttributeEscapes>::new(self.value))
23 }
24}
25
26impl<'a> Attribute<'a> {
27 /// Creates an owned attribute out of this borrowed one.
28 #[inline]
29 #[must_use]
30 pub fn to_owned(&self) -> OwnedAttribute {
31 OwnedAttribute {
32 name: self.name.into(),
33 value: self.value.into(),
34 }
35 }
36
37 /// Creates a borrowed attribute using the provided borrowed name and a borrowed string value.
38 #[inline]
39 #[must_use]
40 pub const fn new(name: Name<'a>, value: &'a str) -> Self {
41 Attribute { name, value }
42 }
43}
44
45/// An owned version of an XML attribute.
46///
47/// Consists of an owned qualified name and an owned string value.
48#[derive(Clone, Eq, PartialEq, Hash, Debug)]
49pub struct OwnedAttribute {
50 /// Attribute name.
51 pub name: OwnedName,
52
53 /// Attribute value.
54 pub value: String,
55}
56
57impl OwnedAttribute {
58 /// Returns a borrowed `Attribute` out of this owned one.
59 #[must_use]
60 #[inline]
61 pub fn borrow(&self) -> Attribute<'_> {
62 Attribute {
63 name: self.name.borrow(),
64 value: &self.value,
65 }
66 }
67
68 /// Creates a new owned attribute using the provided owned name and an owned string value.
69 #[inline]
70 pub fn new<S: Into<String>>(name: OwnedName, value: S) -> Self {
71 Self { name, value: value.into() }
72 }
73}
74
75impl fmt::Display for OwnedAttribute {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 write!(f, "{}=\"{}\"", self.name, Escaped::<AttributeEscapes>::new(&self.value))
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::Attribute;
84
85 use crate::name::Name;
86
87 #[test]
88 fn attribute_display() {
89 let attr = Attribute::new(
90 Name::qualified("attribute", "urn:namespace", Some("n")),
91 "its value with > & \" ' < weird symbols",
92 );
93
94 assert_eq!(
95 &*attr.to_string(),
96 "{urn:namespace}n:attribute=\"its value with &gt; &amp; &quot; &apos; &lt; weird symbols\""
97 );
98 }
99}
100