Skip to main content

office_rs/common/
mod.rs

1//! 通用工具模块
2//!
3//! 提供Office文档处理的通用功能,包括:
4//! - XML处理工具
5//! - ZIP文件操作
6//! - 通用数据类型
7//! - 常用常量和工具函数
8
9pub mod types;
10pub mod xml_utils;
11pub mod zip_utils;
12
13// 重新导出常用类型和函数
14pub use types::*;
15
16pub use xml_utils::{
17    NamespaceManager,
18    XmlElement,
19    XmlGenerator,
20    XmlParser,
21    utils as xml_utils_functions,
22};
23
24pub use zip_utils::{ ZipEntry, ZipReader, ZipWriter, utils as zip_utils_functions };
25
26/// Office文档的常见MIME类型
27pub mod mime_types {
28    /// Excel文档MIME类型
29    pub const EXCEL_XLSX: &str =
30        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
31    pub const EXCEL_XLS: &str = "application/vnd.ms-excel";
32
33    /// Word文档MIME类型
34    pub const WORD_DOCX: &str =
35        "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
36    pub const WORD_DOC: &str = "application/msword";
37
38    /// PowerPoint文档MIME类型
39    pub const POWERPOINT_PPTX: &str =
40        "application/vnd.openxmlformats-officedocument.presentationml.presentation";
41    pub const POWERPOINT_PPT: &str = "application/vnd.ms-powerpoint";
42}
43
44/// Office文档的常见文件扩展名
45pub mod file_extensions {
46    /// Excel文件扩展名
47    pub const EXCEL_EXTENSIONS: &[&str] = &["xlsx", "xls", "xlsm", "xlsb"];
48
49    /// Word文件扩展名
50    pub const WORD_EXTENSIONS: &[&str] = &["docx", "doc", "docm", "dotx", "dotm"];
51
52    /// PowerPoint文件扩展名
53    pub const POWERPOINT_EXTENSIONS: &[&str] = &["pptx", "ppt", "pptm", "potx", "potm"];
54
55    /// 所有支持的Office文件扩展名
56    pub const ALL_OFFICE_EXTENSIONS: &[&str] = &[
57        "xlsx",
58        "xls",
59        "xlsm",
60        "xlsb",
61        "docx",
62        "doc",
63        "docm",
64        "dotx",
65        "dotm",
66        "pptx",
67        "ppt",
68        "pptm",
69        "potx",
70        "potm",
71    ];
72}
73
74/// Office文档的常见命名空间
75pub mod namespaces {
76    /// Excel相关命名空间
77    pub mod excel {
78        pub const MAIN: &str = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
79        pub const RELATIONSHIPS: &str =
80            "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
81        pub const SHARED_STRINGS: &str =
82            "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
83        pub const STYLES: &str = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
84    }
85
86    /// Word相关命名空间
87    pub mod word {
88        pub const MAIN: &str = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
89        pub const RELATIONSHIPS: &str =
90            "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
91        pub const DOCUMENT: &str = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
92    }
93
94    /// PowerPoint相关命名空间
95    pub mod powerpoint {
96        pub const MAIN: &str = "http://schemas.openxmlformats.org/presentationml/2006/main";
97        pub const RELATIONSHIPS: &str =
98            "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
99        pub const SLIDE: &str = "http://schemas.openxmlformats.org/presentationml/2006/main";
100    }
101
102    /// 通用命名空间
103    pub mod common {
104        pub const PACKAGE_RELATIONSHIPS: &str =
105            "http://schemas.openxmlformats.org/package/2006/relationships";
106        pub const CONTENT_TYPES: &str =
107            "http://schemas.openxmlformats.org/package/2006/content-types";
108        pub const CORE_PROPERTIES: &str =
109            "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
110        pub const DUBLIN_CORE: &str = "http://purl.org/dc/elements/1.1/";
111        pub const DUBLIN_CORE_TERMS: &str = "http://purl.org/dc/terms/";
112    }
113}
114
115/// 工具函数
116pub mod utils {
117    use crate::error::{ OfficeError, Result };
118    use std::path::Path;
119
120    /// 根据文件扩展名检测Office文档类型
121    #[derive(Debug, Clone, PartialEq)]
122    pub enum OfficeDocumentType {
123        Excel,
124        Word,
125        PowerPoint,
126        Unknown,
127    }
128
129    /// 根据文件路径检测文档类型
130    pub fn detect_document_type<P: AsRef<Path>>(path: P) -> OfficeDocumentType {
131        if
132            let Some(extension) = path
133                .as_ref()
134                .extension()
135                .and_then(|ext| ext.to_str())
136        {
137            let ext_lower = extension.to_lowercase();
138
139            if super::file_extensions::EXCEL_EXTENSIONS.contains(&ext_lower.as_str()) {
140                OfficeDocumentType::Excel
141            } else if super::file_extensions::WORD_EXTENSIONS.contains(&ext_lower.as_str()) {
142                OfficeDocumentType::Word
143            } else if super::file_extensions::POWERPOINT_EXTENSIONS.contains(&ext_lower.as_str()) {
144                OfficeDocumentType::PowerPoint
145            } else {
146                OfficeDocumentType::Unknown
147            }
148        } else {
149            OfficeDocumentType::Unknown
150        }
151    }
152
153    /// 验证文件是否为支持的Office文档
154    pub fn is_supported_office_file<P: AsRef<Path>>(path: P) -> bool {
155        detect_document_type(path) != OfficeDocumentType::Unknown
156    }
157
158    /// 获取文档类型对应的MIME类型
159    pub fn get_mime_type(doc_type: &OfficeDocumentType, is_legacy: bool) -> Option<&'static str> {
160        match (doc_type, is_legacy) {
161            (OfficeDocumentType::Excel, false) => Some(super::mime_types::EXCEL_XLSX),
162            (OfficeDocumentType::Excel, true) => Some(super::mime_types::EXCEL_XLS),
163            (OfficeDocumentType::Word, false) => Some(super::mime_types::WORD_DOCX),
164            (OfficeDocumentType::Word, true) => Some(super::mime_types::WORD_DOC),
165            (OfficeDocumentType::PowerPoint, false) => Some(super::mime_types::POWERPOINT_PPTX),
166            (OfficeDocumentType::PowerPoint, true) => Some(super::mime_types::POWERPOINT_PPT),
167            (OfficeDocumentType::Unknown, _) => None,
168        }
169    }
170
171    /// 标准化文件路径(将反斜杠转换为正斜杠)
172    pub fn normalize_path(path: &str) -> String {
173        path.replace('\\', "/")
174    }
175
176    /// 验证XML元素名称是否有效
177    pub fn validate_xml_name(name: &str) -> Result<()> {
178        if super::xml_utils_functions::is_valid_xml_name(name) {
179            Ok(())
180        } else {
181            Err(OfficeError::Format(format!("无效的XML元素名称: {}", name)))
182        }
183    }
184
185    /// 安全地创建目录路径
186    pub fn ensure_directory_exists<P: AsRef<Path>>(path: P) -> Result<()> {
187        std::fs::create_dir_all(&path).map_err(|e| OfficeError::Io(e))
188    }
189
190    /// 生成唯一的临时文件名
191    pub fn generate_temp_filename(prefix: &str, extension: &str) -> String {
192        use std::time::{ SystemTime, UNIX_EPOCH };
193
194        let timestamp = SystemTime::now()
195            .duration_since(UNIX_EPOCH)
196            .unwrap_or_default()
197            .as_millis();
198
199        format!("{}_{}_{}.{}", prefix, timestamp, fastrand::u32(..), extension)
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206
207    #[test]
208    fn test_document_type_detection() {
209        assert_eq!(utils::detect_document_type("test.xlsx"), utils::OfficeDocumentType::Excel);
210        assert_eq!(utils::detect_document_type("test.docx"), utils::OfficeDocumentType::Word);
211        assert_eq!(utils::detect_document_type("test.pptx"), utils::OfficeDocumentType::PowerPoint);
212        assert_eq!(utils::detect_document_type("test.txt"), utils::OfficeDocumentType::Unknown);
213    }
214
215    #[test]
216    fn test_mime_type_detection() {
217        let excel_type = utils::OfficeDocumentType::Excel;
218        assert_eq!(utils::get_mime_type(&excel_type, false), Some(mime_types::EXCEL_XLSX));
219        assert_eq!(utils::get_mime_type(&excel_type, true), Some(mime_types::EXCEL_XLS));
220    }
221
222    #[test]
223    fn test_path_normalization() {
224        assert_eq!(utils::normalize_path("folder\\file.xml"), "folder/file.xml");
225        assert_eq!(utils::normalize_path("folder/file.xml"), "folder/file.xml");
226    }
227}