sheetkit_xml/
content_types.rs1use serde::{Deserialize, Serialize};
6
7use crate::namespaces;
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11#[serde(rename = "Types")]
12pub struct ContentTypes {
13 #[serde(rename = "@xmlns")]
14 pub xmlns: String,
15
16 #[serde(rename = "Default", default)]
17 pub defaults: Vec<ContentTypeDefault>,
18
19 #[serde(rename = "Override", default)]
20 pub overrides: Vec<ContentTypeOverride>,
21}
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub struct ContentTypeDefault {
26 #[serde(rename = "@Extension")]
27 pub extension: String,
28
29 #[serde(rename = "@ContentType")]
30 pub content_type: String,
31}
32
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35pub struct ContentTypeOverride {
36 #[serde(rename = "@PartName")]
37 pub part_name: String,
38
39 #[serde(rename = "@ContentType")]
40 pub content_type: String,
41}
42
43impl Default for ContentTypes {
44 fn default() -> Self {
45 Self {
46 xmlns: namespaces::CONTENT_TYPES.to_string(),
47 defaults: vec![
48 ContentTypeDefault {
49 extension: "rels".to_string(),
50 content_type: mime_types::RELS.to_string(),
51 },
52 ContentTypeDefault {
53 extension: "xml".to_string(),
54 content_type: mime_types::XML.to_string(),
55 },
56 ],
57 overrides: vec![
58 ContentTypeOverride {
59 part_name: "/xl/workbook.xml".to_string(),
60 content_type: mime_types::WORKBOOK.to_string(),
61 },
62 ContentTypeOverride {
63 part_name: "/xl/worksheets/sheet1.xml".to_string(),
64 content_type: mime_types::WORKSHEET.to_string(),
65 },
66 ContentTypeOverride {
67 part_name: "/xl/styles.xml".to_string(),
68 content_type: mime_types::STYLES.to_string(),
69 },
70 ContentTypeOverride {
71 part_name: "/xl/sharedStrings.xml".to_string(),
72 content_type: mime_types::SHARED_STRINGS.to_string(),
73 },
74 ],
75 }
76 }
77}
78
79pub mod mime_types {
81 pub const RELS: &str = "application/vnd.openxmlformats-package.relationships+xml";
83 pub const XML: &str = "application/xml";
84 pub const PNG: &str = "image/png";
85 pub const JPEG: &str = "image/jpeg";
86 pub const GIF: &str = "image/gif";
87 pub const BMP: &str = "image/bmp";
88 pub const ICO: &str = "image/x-icon";
89 pub const TIFF: &str = "image/tiff";
90 pub const SVG: &str = "image/svg+xml";
91 pub const EMF: &str = "image/x-emf";
92 pub const EMZ: &str = "image/x-emz";
93 pub const WMF: &str = "image/x-wmf";
94 pub const WMZ: &str = "image/x-wmz";
95
96 pub const WORKBOOK: &str =
98 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
99 pub const WORKBOOK_MACRO: &str = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
100 pub const WORKBOOK_TEMPLATE: &str =
101 "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml";
102
103 pub const WORKSHEET: &str =
105 "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
106 pub const CHARTSHEET: &str =
107 "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml";
108
109 pub const SHARED_STRINGS: &str =
111 "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
112 pub const STYLES: &str =
113 "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml";
114 pub const THEME: &str = "application/vnd.openxmlformats-officedocument.theme+xml";
115
116 pub const CHART: &str = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
118 pub const DRAWING: &str = "application/vnd.openxmlformats-officedocument.drawing+xml";
119
120 pub const TABLE: &str = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml";
122
123 pub const VML_DRAWING: &str = "application/vnd.openxmlformats-officedocument.vmlDrawing";
125
126 pub const COMMENTS: &str =
128 "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml";
129
130 pub const PIVOT_TABLE: &str =
132 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml";
133 pub const PIVOT_CACHE_DEFINITION: &str =
134 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml";
135 pub const PIVOT_CACHE_RECORDS: &str =
136 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml";
137
138 pub const CORE_PROPERTIES: &str = "application/vnd.openxmlformats-package.core-properties+xml";
140 pub const EXTENDED_PROPERTIES: &str =
141 "application/vnd.openxmlformats-officedocument.extended-properties+xml";
142 pub const CUSTOM_PROPERTIES: &str =
143 "application/vnd.openxmlformats-officedocument.custom-properties+xml";
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_content_types_default() {
152 let ct = ContentTypes::default();
153 assert_eq!(ct.xmlns, namespaces::CONTENT_TYPES);
154 assert_eq!(ct.defaults.len(), 2);
155 assert_eq!(ct.overrides.len(), 4);
156
157 assert_eq!(ct.defaults[0].extension, "rels");
159 assert_eq!(ct.defaults[1].extension, "xml");
160
161 let part_names: Vec<&str> = ct.overrides.iter().map(|o| o.part_name.as_str()).collect();
163 assert!(part_names.contains(&"/xl/workbook.xml"));
164 assert!(part_names.contains(&"/xl/worksheets/sheet1.xml"));
165 assert!(part_names.contains(&"/xl/styles.xml"));
166 assert!(part_names.contains(&"/xl/sharedStrings.xml"));
167 }
168
169 #[test]
170 fn test_content_types_roundtrip() {
171 let ct = ContentTypes::default();
172 let xml = quick_xml::se::to_string(&ct).unwrap();
173 let parsed: ContentTypes = quick_xml::de::from_str(&xml).unwrap();
174 assert_eq!(ct.defaults.len(), parsed.defaults.len());
175 assert_eq!(ct.overrides.len(), parsed.overrides.len());
176 assert_eq!(ct.xmlns, parsed.xmlns);
177 }
178
179 #[test]
180 fn test_content_types_serialize_structure() {
181 let ct = ContentTypes::default();
182 let xml = quick_xml::se::to_string(&ct).unwrap();
183
184 assert!(xml.contains("<Types"));
186 assert!(xml.contains("xmlns="));
187 assert!(xml.contains("<Default"));
189 assert!(xml.contains("Extension="));
190 assert!(xml.contains("ContentType="));
191 assert!(xml.contains("<Override"));
193 assert!(xml.contains("PartName="));
194 }
195
196 #[test]
197 fn test_parse_real_excel_content_types() {
198 let xml = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
199<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
200 <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
201 <Default Extension="xml" ContentType="application/xml"/>
202 <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
203 <Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
204 <Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
205 <Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
206</Types>"#;
207
208 let parsed: ContentTypes = quick_xml::de::from_str(xml).unwrap();
209 assert_eq!(parsed.defaults.len(), 2);
210 assert_eq!(parsed.overrides.len(), 4);
211 assert_eq!(parsed.defaults[0].extension, "rels");
212 assert_eq!(parsed.overrides[0].part_name, "/xl/workbook.xml");
213 }
214
215 #[test]
216 fn test_content_type_default_fields() {
217 let default = ContentTypeDefault {
218 extension: "png".to_string(),
219 content_type: mime_types::PNG.to_string(),
220 };
221 let xml = quick_xml::se::to_string(&default).unwrap();
222 assert!(xml.contains("Extension=\"png\""));
223 assert!(xml.contains("ContentType=\"image/png\""));
224 }
225}