1use hard_xml::{XmlRead, XmlResult, XmlWrite, XmlWriter};
7use std::borrow::Cow;
8use std::io::Write;
9
10use crate::__string_enum;
11use crate::schema::SCHEMA_RELATIONSHIPS;
12
13#[derive(Debug, Default, XmlRead, Clone)]
14#[xml(tag = "Relationships")]
15pub struct Relationships<'a> {
16 #[xml(child = "Relationship")]
17 pub relationships: Vec<Relationship<'a>>,
18}
19
20impl<'a> XmlWrite for Relationships<'a> {
21 fn to_writer<W: Write>(&self, writer: &mut XmlWriter<W>) -> XmlResult<()> {
22 let Relationships { relationships } = self;
23
24 log::debug!("[Relationships] Started writing.");
25 let _ = write!(writer.inner, "{}", crate::schema::SCHEMA_XML);
26
27 writer.write_element_start("Relationships")?;
28
29 writer.write_attribute("xmlns", SCHEMA_RELATIONSHIPS)?;
30
31 if relationships.is_empty() {
32 writer.write_element_end_empty()?;
33 } else {
34 writer.write_element_end_open()?;
35 for ele in relationships {
36 ele.to_writer(writer)?;
37 }
38 writer.write_element_end_close("Relationships")?;
39 }
40
41 log::debug!("[Relationships] Finished writing.");
42
43 Ok(())
44 }
45}
46
47impl<'a> Relationships<'a> {
48 pub fn add_rel(&mut self, schema: &'a str, target: &'a str) {
49 let has = self.relationships.iter().find(|r| r.target == target);
50 if has.is_none() {
51 let ids: Vec<_> = self
52 .relationships
53 .iter()
54 .map(|r| r.id.to_string())
55 .collect();
56
57 let len = self.relationships.len();
58
59 let mut available = false;
60 let mut id = len;
61 while !available {
62 id += 1;
63 let idstr = format!("rId{}", id);
64 available = !ids.contains(&idstr);
65 }
66
67 self.relationships.push(Relationship {
70 id: format!("rId{}", id).into(),
71 target: target.into(),
72 ty: schema.into(),
73 target_mode: None,
74 });
75 }
76 }
77
78 pub fn add_rel_with_target_mode(
79 &mut self,
80 schema: &'a str,
81 target: &'a str,
82 target_mode: Option<&'a str>,
83 ) {
84 let has = self.relationships.iter().find(|r| r.target == target);
85 if has.is_none() {
86 let ids: Vec<_> = self
87 .relationships
88 .iter()
89 .map(|r| r.id.to_string())
90 .collect();
91
92 let len = self.relationships.len();
93
94 let mut available = false;
95 let mut id = len;
96 while !available {
97 id += 1;
98 let idstr = format!("rId{}", id);
99 available = !ids.contains(&idstr);
100 }
101
102 self.relationships.push(Relationship {
105 id: format!("rId{}", id).into(),
106 target: target.into(),
107 ty: schema.into(),
108 target_mode: TargetMode::from_str(target_mode),
109 });
110 }
111 }
112
113 pub fn get_target(&self, id: &str) -> Option<&str> {
114 self.relationships
115 .iter()
116 .find(|r| r.id == id)
117 .map(|r| &*r.target)
118 }
119}
120
121#[derive(Debug, Clone, PartialEq)]
122#[cfg_attr(test, derive(Eq))]
123pub enum TargetMode {
124 Internal,
125 External,
126}
127
128__string_enum! {
129 TargetMode {
130 Internal = "Internal",
131 External = "External",
132 }
133}
134
135impl From<&str> for TargetMode {
136 fn from(value: &str) -> Self {
137 match value {
138 "External" => TargetMode::External,
139 _ => TargetMode::Internal,
140 }
141 }
142}
143
144impl TargetMode {
145 fn from_str(option_str: Option<&str>) -> Option<Self> {
146 match option_str {
147 Some(s) => Some(s.into()),
148 None => None,
149 }
150 }
151}
152
153#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
154#[xml(tag = "Relationship")]
155pub struct Relationship<'a> {
156 #[xml(attr = "Id")]
157 pub id: Cow<'a, str>,
158 #[xml(attr = "Target")]
159 pub target: Cow<'a, str>,
160 #[xml(attr = "Type")]
161 pub ty: Cow<'a, str>,
162 #[xml(attr = "TargetMode")]
163 pub target_mode: Option<TargetMode>,
164}