xsd_parser/models/schema/
mod.rs

1//! The `schema` module contains internal representations of XML Schema (XSD) structures.
2//!
3//! This module defines types that model loaded XML schemas, namespaces, and their relationships,
4//! serving as the output of the [`Parser`](crate::Parser) and input to the
5//! [`Interpreter`](crate::Interpreter).
6//!
7//! It manages the resolution of namespaces and tracks schema documents across multiple sources.
8
9pub mod xs;
10
11mod occurs;
12mod qname;
13
14use std::collections::btree_map::{BTreeMap, Iter, IterMut};
15
16use url::Url;
17
18use xsd_parser_types::misc::{Namespace, NamespacePrefix};
19
20use self::xs::Schema;
21
22pub use self::occurs::{MaxOccurs, MinOccurs};
23pub use self::qname::QName;
24
25/// Top-level structure for managing loaded XML schema files and associated namespaces.
26///
27/// This type is created and populated by the [`Parser`](crate::Parser), and used
28/// by the [`Interpreter`](crate::Interpreter) to resolve schema components into
29/// meaningful Rust types.
30///
31/// It tracks all loaded schemas, the namespaces they belong to, and which prefixes
32/// are associated with which namespace URIs. Each namespace and schema is assigned
33/// a unique ID (`NamespaceId`, `SchemaId`) to allow efficient lookup and association.
34///
35/// This type supports iterating over loaded schemas and namespaces,
36/// as well as resolving prefixes and namespaces during interpretation.
37#[derive(Default, Debug)]
38pub struct Schemas {
39    pub(crate) schemas: SchemaFiles,
40    pub(crate) namespace_infos: NamespaceInfos,
41
42    pub(crate) known_prefixes: NamespacePrefixes,
43    pub(crate) known_namespaces: Namespaces,
44
45    pub(crate) next_schema_id: usize,
46    pub(crate) next_namespace_id: usize,
47}
48
49/// Contains the information for a specific namespace.
50#[derive(Debug)]
51pub struct NamespaceInfo {
52    /// First used/known prefix of the namespace or `None` if it is unknown.
53    pub prefix: Option<NamespacePrefix>,
54
55    /// URI of the namespace or `None` if it is the global or no namespace.
56    pub namespace: Option<Namespace>,
57
58    /// Schema files associated with this namespace.
59    pub schemas: Vec<SchemaId>,
60
61    /// User defined name to use for module generation for this namespace.
62    pub module_name: Option<String>,
63}
64
65/// Contains information for a specific schema
66#[derive(Debug)]
67pub struct SchemaInfo {
68    /// Name of the schema.
69    pub name: Option<String>,
70
71    /// The actual schema data.
72    pub schema: Schema,
73
74    /// Location the schema was load from.
75    pub location: Option<Url>,
76
77    /// Id of the namespace this schema belongs to.
78    pub(crate) namespace_id: NamespaceId,
79}
80
81/// Represents an unique id for a XML schema.
82#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
83pub struct SchemaId(pub usize);
84
85/// Represents a unique id for a XML namespace.
86#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
87pub struct NamespaceId(pub usize);
88
89/// Map of [`SchemaId`] to [`Schema`]
90pub type SchemaFiles = BTreeMap<SchemaId, SchemaInfo>;
91
92/// Map of [`NamespaceId`] to [`NamespaceInfo`]
93pub type NamespaceInfos = BTreeMap<NamespaceId, NamespaceInfo>;
94
95/// Map of [`Namespace`] to [`NamespaceId`]
96pub type Namespaces = BTreeMap<Option<Namespace>, NamespaceId>;
97
98/// Map of [`NamespacePrefix`] to [`NamespaceId`]
99pub type NamespacePrefixes = BTreeMap<NamespacePrefix, NamespaceId>;
100
101/* Schemas */
102
103impl Schemas {
104    /// Returns an iterator over all schemas stored in this structure.
105    pub fn schemas(&self) -> Iter<'_, SchemaId, SchemaInfo> {
106        self.schemas.iter()
107    }
108
109    /// Returns a mutable iterator over all schemas stored in this structure.
110    pub fn schemas_mut(&mut self) -> IterMut<'_, SchemaId, SchemaInfo> {
111        self.schemas.iter_mut()
112    }
113
114    /// Returns an iterator over all namespace information instances stored
115    /// in this structure.
116    pub fn namespaces(&self) -> Iter<'_, NamespaceId, NamespaceInfo> {
117        self.namespace_infos.iter()
118    }
119
120    /// Returns a reference to a specific schema by using the schema id,
121    /// or `None` if the schema is not known.
122    #[must_use]
123    pub fn get_schema(&self, id: &SchemaId) -> Option<&SchemaInfo> {
124        self.schemas.get(id)
125    }
126
127    /// Returns a mutable reference to a specific schema by using the schema id,
128    /// or `None` if the schema is not known.
129    #[must_use]
130    pub fn get_schema_mut(&mut self, id: &SchemaId) -> Option<&mut SchemaInfo> {
131        self.schemas.get_mut(id)
132    }
133
134    /// Returns a reference to a specific namespace information instance by using
135    /// the namespace id.
136    #[must_use]
137    pub fn get_namespace_info(&self, id: &NamespaceId) -> Option<&NamespaceInfo> {
138        self.namespace_infos.get(id)
139    }
140
141    /// Returns a mutable reference to a specific namespace information instance
142    /// by using the namespace id.
143    #[must_use]
144    pub fn get_namespace_info_mut(&mut self, id: &NamespaceId) -> Option<&mut NamespaceInfo> {
145        self.namespace_infos.get_mut(id)
146    }
147
148    /// Returns a reference to a specific namespace information instance by using
149    /// the namespace URI, or `None` if the schema is not known.
150    #[must_use]
151    pub fn get_namespace_info_by_namespace(
152        &self,
153        ns: &Option<Namespace>,
154    ) -> Option<&NamespaceInfo> {
155        let id = self.resolve_namespace(ns)?;
156
157        self.get_namespace_info(&id)
158    }
159
160    /// Try to resolve the namespace prefix to a namespace id.
161    ///
162    /// Returns the namespace id of the given namespace `prefix`, or `None`.
163    #[must_use]
164    pub fn resolve_prefix(&self, prefix: &NamespacePrefix) -> Option<NamespaceId> {
165        Some(*self.known_prefixes.get(prefix)?)
166    }
167
168    /// Try to resolve the namespace to a namespace id.
169    ///
170    /// Returns the namespace id of the given namespace `ns`, or `None`.
171    #[must_use]
172    pub fn resolve_namespace(&self, ns: &Option<Namespace>) -> Option<NamespaceId> {
173        Some(*self.known_namespaces.get(ns)?)
174    }
175}
176
177/* NamespaceInfo */
178
179impl NamespaceInfo {
180    /// Create a new [`NamespaceInfo`] instance from the passed `namespace`.
181    #[must_use]
182    pub fn new(namespace: Option<Namespace>) -> Self {
183        Self {
184            prefix: None,
185            namespace,
186            schemas: Vec::new(),
187            module_name: None,
188        }
189    }
190
191    /// Return the name of the namespace.
192    ///
193    /// This is either the [custom name](Self::module_name) or the namespace
194    /// [`prefix`](Self::prefix).
195    #[must_use]
196    pub fn name(&self) -> Option<String> {
197        self.module_name
198            .clone()
199            .or_else(|| self.prefix.as_ref().map(ToString::to_string))
200    }
201}
202
203/* SchemaInfo */
204
205impl SchemaInfo {
206    /// Get the id of the namespace this schema belongs to.
207    #[must_use]
208    pub fn namespace_id(&self) -> NamespaceId {
209        self.namespace_id
210    }
211}