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}