pub mod types;
pub mod xml_utils;
pub mod zip_utils;
pub use types::*;
pub use xml_utils::{
NamespaceManager,
XmlElement,
XmlGenerator,
XmlParser,
utils as xml_utils_functions,
};
pub use zip_utils::{ ZipEntry, ZipReader, ZipWriter, utils as zip_utils_functions };
pub mod mime_types {
pub const EXCEL_XLSX: &str =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
pub const EXCEL_XLS: &str = "application/vnd.ms-excel";
pub const WORD_DOCX: &str =
"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
pub const WORD_DOC: &str = "application/msword";
pub const POWERPOINT_PPTX: &str =
"application/vnd.openxmlformats-officedocument.presentationml.presentation";
pub const POWERPOINT_PPT: &str = "application/vnd.ms-powerpoint";
}
pub mod file_extensions {
pub const EXCEL_EXTENSIONS: &[&str] = &["xlsx", "xls", "xlsm", "xlsb"];
pub const WORD_EXTENSIONS: &[&str] = &["docx", "doc", "docm", "dotx", "dotm"];
pub const POWERPOINT_EXTENSIONS: &[&str] = &["pptx", "ppt", "pptm", "potx", "potm"];
pub const ALL_OFFICE_EXTENSIONS: &[&str] = &[
"xlsx",
"xls",
"xlsm",
"xlsb",
"docx",
"doc",
"docm",
"dotx",
"dotm",
"pptx",
"ppt",
"pptm",
"potx",
"potm",
];
}
pub mod namespaces {
pub mod excel {
pub const MAIN: &str = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
pub const RELATIONSHIPS: &str =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
pub const SHARED_STRINGS: &str =
"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
pub const STYLES: &str = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
}
pub mod word {
pub const MAIN: &str = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
pub const RELATIONSHIPS: &str =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
pub const DOCUMENT: &str = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
}
pub mod powerpoint {
pub const MAIN: &str = "http://schemas.openxmlformats.org/presentationml/2006/main";
pub const RELATIONSHIPS: &str =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
pub const SLIDE: &str = "http://schemas.openxmlformats.org/presentationml/2006/main";
}
pub mod common {
pub const PACKAGE_RELATIONSHIPS: &str =
"http://schemas.openxmlformats.org/package/2006/relationships";
pub const CONTENT_TYPES: &str =
"http://schemas.openxmlformats.org/package/2006/content-types";
pub const CORE_PROPERTIES: &str =
"http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
pub const DUBLIN_CORE: &str = "http://purl.org/dc/elements/1.1/";
pub const DUBLIN_CORE_TERMS: &str = "http://purl.org/dc/terms/";
}
}
pub mod utils {
use crate::error::{ OfficeError, Result };
use std::path::Path;
#[derive(Debug, Clone, PartialEq)]
pub enum OfficeDocumentType {
Excel,
Word,
PowerPoint,
Unknown,
}
pub fn detect_document_type<P: AsRef<Path>>(path: P) -> OfficeDocumentType {
if
let Some(extension) = path
.as_ref()
.extension()
.and_then(|ext| ext.to_str())
{
let ext_lower = extension.to_lowercase();
if super::file_extensions::EXCEL_EXTENSIONS.contains(&ext_lower.as_str()) {
OfficeDocumentType::Excel
} else if super::file_extensions::WORD_EXTENSIONS.contains(&ext_lower.as_str()) {
OfficeDocumentType::Word
} else if super::file_extensions::POWERPOINT_EXTENSIONS.contains(&ext_lower.as_str()) {
OfficeDocumentType::PowerPoint
} else {
OfficeDocumentType::Unknown
}
} else {
OfficeDocumentType::Unknown
}
}
pub fn is_supported_office_file<P: AsRef<Path>>(path: P) -> bool {
detect_document_type(path) != OfficeDocumentType::Unknown
}
pub fn get_mime_type(doc_type: &OfficeDocumentType, is_legacy: bool) -> Option<&'static str> {
match (doc_type, is_legacy) {
(OfficeDocumentType::Excel, false) => Some(super::mime_types::EXCEL_XLSX),
(OfficeDocumentType::Excel, true) => Some(super::mime_types::EXCEL_XLS),
(OfficeDocumentType::Word, false) => Some(super::mime_types::WORD_DOCX),
(OfficeDocumentType::Word, true) => Some(super::mime_types::WORD_DOC),
(OfficeDocumentType::PowerPoint, false) => Some(super::mime_types::POWERPOINT_PPTX),
(OfficeDocumentType::PowerPoint, true) => Some(super::mime_types::POWERPOINT_PPT),
(OfficeDocumentType::Unknown, _) => None,
}
}
pub fn normalize_path(path: &str) -> String {
path.replace('\\', "/")
}
pub fn validate_xml_name(name: &str) -> Result<()> {
if super::xml_utils_functions::is_valid_xml_name(name) {
Ok(())
} else {
Err(OfficeError::Format(format!("无效的XML元素名称: {}", name)))
}
}
pub fn ensure_directory_exists<P: AsRef<Path>>(path: P) -> Result<()> {
std::fs::create_dir_all(&path).map_err(|e| OfficeError::Io(e))
}
pub fn generate_temp_filename(prefix: &str, extension: &str) -> String {
use std::time::{ SystemTime, UNIX_EPOCH };
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis();
format!("{}_{}_{}.{}", prefix, timestamp, fastrand::u32(..), extension)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_document_type_detection() {
assert_eq!(utils::detect_document_type("test.xlsx"), utils::OfficeDocumentType::Excel);
assert_eq!(utils::detect_document_type("test.docx"), utils::OfficeDocumentType::Word);
assert_eq!(utils::detect_document_type("test.pptx"), utils::OfficeDocumentType::PowerPoint);
assert_eq!(utils::detect_document_type("test.txt"), utils::OfficeDocumentType::Unknown);
}
#[test]
fn test_mime_type_detection() {
let excel_type = utils::OfficeDocumentType::Excel;
assert_eq!(utils::get_mime_type(&excel_type, false), Some(mime_types::EXCEL_XLSX));
assert_eq!(utils::get_mime_type(&excel_type, true), Some(mime_types::EXCEL_XLS));
}
#[test]
fn test_path_normalization() {
assert_eq!(utils::normalize_path("folder\\file.xml"), "folder/file.xml");
assert_eq!(utils::normalize_path("folder/file.xml"), "folder/file.xml");
}
}