Skip to main content

ooxml_xml/
lib.rs

1//! Shared XML utilities for the ooxml library.
2//!
3//! This crate provides common XML types and utilities used across OOXML format crates
4//! for features like roundtrip fidelity (preserving unknown elements/attributes).
5
6use quick_xml::events::{BytesEnd, BytesStart};
7use quick_xml::{Reader, Writer};
8use std::io::{BufRead, Write};
9
10mod raw_xml;
11pub mod serde_helpers;
12
13pub use raw_xml::{PositionedAttr, PositionedNode, RawXmlElement, RawXmlNode, RawXmlStreamReader};
14pub use serde_helpers::{ooxml_bool, ooxml_bool_required};
15
16/// Error type for XML operations.
17#[derive(Debug, thiserror::Error)]
18pub enum Error {
19    #[error("XML error: {0}")]
20    Xml(#[from] quick_xml::Error),
21    #[error("IO error: {0}")]
22    Io(#[from] std::io::Error),
23    #[error("invalid XML: {0}")]
24    Invalid(String),
25}
26
27/// Result type for XML operations.
28pub type Result<T> = std::result::Result<T, Error>;
29
30/// Error type for XML parsing (used by generated parsers).
31#[derive(Debug, thiserror::Error)]
32pub enum ParseError {
33    #[error("XML error: {0}")]
34    Xml(#[from] quick_xml::Error),
35    #[error("raw XML error: {0}")]
36    RawXml(#[from] Error),
37    #[error("unexpected element: {0}")]
38    UnexpectedElement(String),
39    #[error("missing attribute: {0}")]
40    MissingAttribute(String),
41    #[error("invalid value: {0}")]
42    InvalidValue(String),
43}
44
45/// Error type for XML serialization (used by generated serializers).
46#[derive(Debug, thiserror::Error)]
47pub enum SerializeError {
48    #[error("XML error: {0}")]
49    Xml(#[from] quick_xml::Error),
50    #[error("IO error: {0}")]
51    Io(#[from] std::io::Error),
52    #[error("raw XML error: {0}")]
53    RawXml(#[from] Error),
54}
55
56/// Trait for types that can be parsed from XML elements.
57///
58/// Implemented by generated OOXML types to enable event-based parsing.
59pub trait FromXml: Sized {
60    /// Parse from an XML reader positioned at the start tag.
61    ///
62    /// - `reader`: The XML reader
63    /// - `start_tag`: The start tag that was just read
64    /// - `is_empty`: True if this is an empty element (e.g., `<foo/>`)
65    fn from_xml<R: BufRead>(
66        reader: &mut Reader<R>,
67        start_tag: &BytesStart,
68        is_empty: bool,
69    ) -> std::result::Result<Self, ParseError>;
70}
71
72/// Trait for types that can be serialized to XML elements.
73///
74/// Implemented by generated OOXML types to enable roundtrip serialization.
75pub trait ToXml {
76    /// Write attributes onto the start tag and return it.
77    fn write_attrs<'a>(&self, start: BytesStart<'a>) -> BytesStart<'a> {
78        start
79    }
80
81    /// Write child elements and text content inside the element.
82    fn write_children<W: Write>(
83        &self,
84        _writer: &mut Writer<W>,
85    ) -> std::result::Result<(), SerializeError> {
86        Ok(())
87    }
88
89    /// Whether this element has no children (self-closing).
90    fn is_empty_element(&self) -> bool {
91        false
92    }
93
94    /// Write a complete element: `<tag attrs>children</tag>` or `<tag attrs/>`.
95    fn write_element<W: Write>(
96        &self,
97        tag: &str,
98        writer: &mut Writer<W>,
99    ) -> std::result::Result<(), SerializeError> {
100        use quick_xml::events::Event;
101        let start = BytesStart::new(tag);
102        let start = self.write_attrs(start);
103        if self.is_empty_element() {
104            writer.write_event(Event::Empty(start))?;
105        } else {
106            writer.write_event(Event::Start(start))?;
107            self.write_children(writer)?;
108            writer.write_event(Event::End(BytesEnd::new(tag)))?;
109        }
110        Ok(())
111    }
112}
113
114// Blanket implementation for Box<T> where T: ToXml
115impl<T: ToXml> ToXml for Box<T> {
116    fn write_attrs<'a>(&self, start: BytesStart<'a>) -> BytesStart<'a> {
117        (**self).write_attrs(start)
118    }
119
120    fn write_children<W: Write>(
121        &self,
122        writer: &mut Writer<W>,
123    ) -> std::result::Result<(), SerializeError> {
124        (**self).write_children(writer)
125    }
126
127    fn is_empty_element(&self) -> bool {
128        (**self).is_empty_element()
129    }
130
131    fn write_element<W: Write>(
132        &self,
133        tag: &str,
134        writer: &mut Writer<W>,
135    ) -> std::result::Result<(), SerializeError> {
136        (**self).write_element(tag, writer)
137    }
138}