xsd_parser/schema/
mod.rs

1//! The `schema` module contains the XML schema types.
2
3pub mod xs;
4
5mod namespace;
6mod namespace_prefix;
7mod occurs;
8mod qname;
9
10use std::borrow::Cow;
11use std::collections::btree_map::{BTreeMap, Entry, Iter};
12
13use self::xs::Schema;
14
15pub use namespace::Namespace;
16pub use namespace_prefix::NamespacePrefix;
17pub use occurs::{MaxOccurs, MinOccurs};
18pub use qname::QName;
19
20/// Represents the XML schema information load from different sources.
21///
22/// This structure is usually created by the [`Parser`](crate::parser::Parser).
23/// It is the used by the [`Interpreter`](crate::interpreter::Interpreter) to
24/// generate the more common [`Types`](crate::types::Types) structure out of it.
25#[derive(Default, Debug)]
26pub struct Schemas {
27    schemas: SchemaFiles,
28    namespace_infos: NamespaceInfos,
29
30    known_prefixes: NamespacePrefixes,
31    known_namespaces: Namespaces,
32
33    next_schema_id: usize,
34    next_namespace_id: usize,
35}
36
37/// Contians the information for a specific namespace.
38#[derive(Debug)]
39pub struct NamespaceInfo {
40    /// First used/known prefix of the namespace or `None` if it is unknown.
41    pub prefix: Option<NamespacePrefix>,
42
43    /// URI of the namespace or `None` if it is the global or no namespace.
44    pub namespace: Option<Namespace>,
45
46    /// Schema files associated with this namespace.
47    pub schemas: Vec<SchemaId>,
48}
49
50/// Represents an unique id for a XML schema.
51#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
52pub struct SchemaId(pub usize);
53
54/// Represents a unique id for a XML namespace.
55#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
56pub struct NamespaceId(pub usize);
57
58/// Map of [`SchemaId`] to [`Schema`]
59pub type SchemaFiles = BTreeMap<SchemaId, Schema>;
60
61/// Map of [`NamespaceId`] to [`NamespaceInfo`]
62pub type NamespaceInfos = BTreeMap<NamespaceId, NamespaceInfo>;
63
64/// Map of [`Namespace`] to [`NamespaceId`]
65pub type Namespaces = BTreeMap<Option<Namespace>, NamespaceId>;
66
67/// Map of [`NamespacePrefix`] to [`NamespaceId`]
68pub type NamespacePrefixes = BTreeMap<NamespacePrefix, NamespaceId>;
69
70/* Schemas */
71
72impl Schemas {
73    /// Add a new schema to the schemas structure.
74    ///
75    /// # Errors
76    ///
77    /// Will just forward the errors from [`get_or_create_namespace_info_mut`](Self::get_or_create_namespace_info_mut).
78    pub fn add_schema(
79        &mut self,
80        prefix: Option<NamespacePrefix>,
81        namespace: Option<Namespace>,
82        schema: Schema,
83    ) {
84        let schema_id = SchemaId(self.next_schema_id);
85        let schema_info = self.get_or_create_namespace_info_mut(prefix, namespace);
86        schema_info.schemas.push(schema_id);
87        self.next_schema_id = self.next_schema_id.wrapping_add(1);
88
89        match self.schemas.entry(schema_id) {
90            Entry::Vacant(e) => e.insert(schema),
91            Entry::Occupied(_) => crate::unreachable!(),
92        };
93    }
94
95    /// Get a mutable reference to a [`NamespaceInfo`] or create a new one if needed.
96    pub fn get_or_create_namespace_info_mut(
97        &mut self,
98        prefix: Option<NamespacePrefix>,
99        namespace: Option<Namespace>,
100    ) -> &mut NamespaceInfo {
101        let (ns, id) = match self.known_namespaces.entry(namespace) {
102            Entry::Occupied(e) => {
103                let id = *e.get();
104                let ns = self.namespace_infos.get_mut(&id).unwrap();
105
106                (ns, id)
107            }
108            Entry::Vacant(e) => {
109                let id = NamespaceId(self.next_namespace_id);
110                self.next_namespace_id = self.next_namespace_id.wrapping_add(1);
111
112                let namespace = e.key().clone();
113                e.insert(id);
114
115                let ns = match self.namespace_infos.entry(id) {
116                    Entry::Vacant(e) => e.insert(NamespaceInfo::new(namespace)),
117                    Entry::Occupied(_) => crate::unreachable!(),
118                };
119
120                (ns, id)
121            }
122        };
123
124        if let Some(mut prefix) = prefix {
125            if matches!(self.known_prefixes.get(&prefix), Some(x) if *x != id) {
126                let ext = format!("_{}", id.0);
127                let ext = ext.as_bytes();
128
129                let mut p = prefix.0.into_owned();
130                p.extend_from_slice(ext);
131
132                prefix = NamespacePrefix(Cow::Owned(p));
133            }
134
135            self.known_prefixes.insert(prefix.clone(), id);
136
137            if ns.prefix.is_none() {
138                ns.prefix = Some(prefix);
139            }
140        }
141
142        ns
143    }
144
145    /// Returns an iterator over all schemas stored in this structure.
146    pub fn schemas(&self) -> Iter<'_, SchemaId, Schema> {
147        self.schemas.iter()
148    }
149
150    /// Returns an iterator over all namespace information instances stored
151    /// in this structure.
152    pub fn namespaces(&self) -> Iter<'_, NamespaceId, NamespaceInfo> {
153        self.namespace_infos.iter()
154    }
155
156    /// Returns a reference to a specific schema by using the schema id,
157    /// or `None` if the schema is not known.
158    #[must_use]
159    pub fn get_schema(&self, id: &SchemaId) -> Option<&Schema> {
160        self.schemas.get(id)
161    }
162
163    /// Returns a reference to a specific namespace information instance by using
164    /// the namespace id, or `None` if the schema is not known.
165    #[must_use]
166    pub fn get_namespace_info(&self, id: &NamespaceId) -> Option<&NamespaceInfo> {
167        self.namespace_infos.get(id)
168    }
169
170    /// Returns a reference to a specific namespace information instance by using
171    /// the namespace URI, or `None` if the schema is not known.
172    #[must_use]
173    pub fn get_namespace_info_by_namespace(
174        &self,
175        ns: &Option<Namespace>,
176    ) -> Option<&NamespaceInfo> {
177        let id = self.resolve_namespace(ns)?;
178
179        self.get_namespace_info(&id)
180    }
181
182    /// Try to resolve the namespace prefix to a namespace id.
183    ///
184    /// Returns the namespace id of the given namespace `prefix`, or `None`.
185    #[must_use]
186    pub fn resolve_prefix(&self, prefix: &NamespacePrefix) -> Option<NamespaceId> {
187        Some(*self.known_prefixes.get(prefix)?)
188    }
189
190    /// Try to resolve the namespace to a namespace id.
191    ///
192    /// Returns the namespace id of the given namespace `ns`, or `None`.
193    #[must_use]
194    pub fn resolve_namespace(&self, ns: &Option<Namespace>) -> Option<NamespaceId> {
195        Some(*self.known_namespaces.get(ns)?)
196    }
197}
198
199/* NamespaceInfo */
200
201impl NamespaceInfo {
202    /// Create a new [`NamespaceInfo`] instance from the passed `namespace`.
203    #[must_use]
204    pub fn new(namespace: Option<Namespace>) -> Self {
205        Self {
206            prefix: None,
207            namespace,
208            schemas: Vec::new(),
209        }
210    }
211}