Skip to main content

xsd_schema/schema/
decl.rs

1//! Element and attribute declarations
2//!
3//! This module defines XSD element and attribute declarations.
4
5use crate::ids::{ElementKey, IdentityConstraintKey, NameId, SimpleTypeKey, TypeKey};
6use crate::parser::location::SourceRef;
7use crate::schema::model::DerivationSet;
8
9/// Scope of a declaration
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum DeclarationScope {
12    /// Global declaration (top-level in schema)
13    Global,
14    /// Local declaration (within complex type)
15    Local,
16}
17
18/// Value constraint kind
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum ValueConstraint {
21    /// Default value (can be overridden)
22    Default(String),
23    /// Fixed value (cannot be changed)
24    Fixed(String),
25}
26
27impl ValueConstraint {
28    /// Get the value
29    pub fn value(&self) -> &str {
30        match self {
31            ValueConstraint::Default(v) => v,
32            ValueConstraint::Fixed(v) => v,
33        }
34    }
35
36    /// Check if this is a fixed constraint
37    pub fn is_fixed(&self) -> bool {
38        matches!(self, ValueConstraint::Fixed(_))
39    }
40}
41
42/// Type reference (can be resolved or unresolved)
43#[derive(Debug, Clone)]
44pub enum TypeReference {
45    /// Resolved type key
46    Resolved(TypeKey),
47    /// Unresolved reference (namespace + local name)
48    Unresolved {
49        namespace: Option<NameId>,
50        local_name: NameId,
51    },
52}
53
54/// Element declaration
55///
56/// Represents an xs:element declaration, either global or local.
57#[derive(Debug, Clone)]
58pub struct ElementDecl {
59    /// Element name
60    pub name: NameId,
61
62    /// Target namespace
63    pub target_namespace: Option<NameId>,
64
65    /// Source location for error reporting
66    pub source: Option<SourceRef>,
67
68    /// Declaration scope (global or local)
69    pub scope: DeclarationScope,
70
71    /// Type definition (resolved or reference)
72    pub type_def: Option<TypeReference>,
73
74    /// Value constraint (default or fixed)
75    pub value_constraint: Option<ValueConstraint>,
76
77    /// Nillable flag (allows xsi:nil="true")
78    pub nillable: bool,
79
80    /// Abstract flag (must be substituted)
81    pub is_abstract: bool,
82
83    /// Substitution group affiliation
84    pub substitution_group: Option<ElementRef>,
85
86    /// Disallowed substitutions (block attribute)
87    pub disallowed_substitutions: DerivationSet,
88
89    /// Substitution group exclusions (final attribute)
90    pub substitution_group_exclusions: DerivationSet,
91
92    /// Identity constraints defined on this element
93    pub identity_constraints: Vec<IdentityConstraintKey>,
94
95    /// ID attribute value
96    pub id: Option<String>,
97
98    /// XSD 1.1: Type alternatives (conditional type assignment)
99    pub type_alternatives: Vec<TypeAlternative>,
100
101    /// Form (qualified/unqualified) - for local elements
102    pub form: Option<FormKind>,
103}
104
105/// Reference to an element (for substitution groups)
106#[derive(Debug, Clone)]
107pub enum ElementRef {
108    /// Resolved element key
109    Resolved(ElementKey),
110    /// Unresolved reference
111    Unresolved {
112        namespace: Option<NameId>,
113        local_name: NameId,
114    },
115}
116
117/// XSD 1.1: Type alternative
118#[derive(Debug, Clone)]
119pub struct TypeAlternative {
120    /// XPath test expression
121    pub test: Option<String>,
122    /// Type to use when test passes
123    pub type_def: TypeReference,
124    /// Source location
125    pub source: Option<SourceRef>,
126}
127
128/// Form kind (qualified/unqualified)
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum FormKind {
131    Qualified,
132    Unqualified,
133}
134
135impl ElementDecl {
136    /// Create a new global element declaration
137    pub fn new_global(name: NameId, target_namespace: Option<NameId>) -> Self {
138        Self {
139            name,
140            target_namespace,
141            source: None,
142            scope: DeclarationScope::Global,
143            type_def: None,
144            value_constraint: None,
145            nillable: false,
146            is_abstract: false,
147            substitution_group: None,
148            disallowed_substitutions: DerivationSet::empty(),
149            substitution_group_exclusions: DerivationSet::empty(),
150            identity_constraints: Vec::new(),
151            id: None,
152            type_alternatives: Vec::new(),
153            form: None,
154        }
155    }
156
157    /// Create a new local element declaration
158    pub fn new_local(name: NameId, target_namespace: Option<NameId>) -> Self {
159        Self {
160            name,
161            target_namespace,
162            source: None,
163            scope: DeclarationScope::Local,
164            type_def: None,
165            value_constraint: None,
166            nillable: false,
167            is_abstract: false,
168            substitution_group: None,
169            disallowed_substitutions: DerivationSet::empty(),
170            substitution_group_exclusions: DerivationSet::empty(),
171            identity_constraints: Vec::new(),
172            id: None,
173            type_alternatives: Vec::new(),
174            form: None,
175        }
176    }
177
178    /// Check if this is a global element
179    pub fn is_global(&self) -> bool {
180        self.scope == DeclarationScope::Global
181    }
182
183    /// Check if this is a local element
184    pub fn is_local(&self) -> bool {
185        self.scope == DeclarationScope::Local
186    }
187
188    /// Check if this element can be substituted
189    pub fn is_substitutable(&self) -> bool {
190        !self.is_abstract && self.substitution_group_exclusions.is_empty()
191    }
192}
193
194/// Attribute declaration
195///
196/// Represents an xs:attribute declaration, either global or local.
197#[derive(Debug, Clone)]
198pub struct AttributeDecl {
199    /// Attribute name
200    pub name: NameId,
201
202    /// Target namespace
203    pub target_namespace: Option<NameId>,
204
205    /// Source location for error reporting
206    pub source: Option<SourceRef>,
207
208    /// Declaration scope (global or local)
209    pub scope: DeclarationScope,
210
211    /// Simple type definition (attributes always have simple types)
212    pub type_def: Option<SimpleTypeReference>,
213
214    /// Value constraint (default or fixed)
215    pub value_constraint: Option<ValueConstraint>,
216
217    /// ID attribute value
218    pub id: Option<String>,
219
220    /// Form (qualified/unqualified) - for local attributes
221    pub form: Option<FormKind>,
222
223    /// XSD 1.1: Inheritable attribute (§3.2.6, §3.3.5.6)
224    pub inheritable: bool,
225}
226
227/// Reference to a simple type
228#[derive(Debug, Clone)]
229pub enum SimpleTypeReference {
230    /// Resolved simple type key
231    Resolved(SimpleTypeKey),
232    /// Built-in type
233    BuiltIn(crate::types::simple::BuiltInType),
234    /// Unresolved reference
235    Unresolved {
236        namespace: Option<NameId>,
237        local_name: NameId,
238    },
239}
240
241impl AttributeDecl {
242    /// Create a new global attribute declaration
243    pub fn new_global(name: NameId, target_namespace: Option<NameId>) -> Self {
244        Self {
245            name,
246            target_namespace,
247            source: None,
248            scope: DeclarationScope::Global,
249            type_def: None,
250            value_constraint: None,
251            id: None,
252            form: None,
253            inheritable: false,
254        }
255    }
256
257    /// Create a new local attribute declaration
258    pub fn new_local(name: NameId, target_namespace: Option<NameId>) -> Self {
259        Self {
260            name,
261            target_namespace,
262            source: None,
263            scope: DeclarationScope::Local,
264            type_def: None,
265            value_constraint: None,
266            id: None,
267            form: None,
268            inheritable: false,
269        }
270    }
271
272    /// Check if this is a global attribute
273    pub fn is_global(&self) -> bool {
274        self.scope == DeclarationScope::Global
275    }
276
277    /// Check if this is a local attribute
278    pub fn is_local(&self) -> bool {
279        self.scope == DeclarationScope::Local
280    }
281
282    /// Check if this attribute has a default value
283    pub fn has_default(&self) -> bool {
284        matches!(self.value_constraint, Some(ValueConstraint::Default(_)))
285    }
286
287    /// Check if this attribute has a fixed value
288    pub fn has_fixed(&self) -> bool {
289        matches!(self.value_constraint, Some(ValueConstraint::Fixed(_)))
290    }
291}
292
293/// Notation declaration
294///
295/// Represents an xs:notation declaration.
296#[derive(Debug, Clone)]
297pub struct NotationDecl {
298    /// Notation name
299    pub name: NameId,
300
301    /// Target namespace
302    pub target_namespace: Option<NameId>,
303
304    /// Public identifier
305    pub public: String,
306
307    /// System identifier (optional)
308    pub system: Option<String>,
309
310    /// Source location
311    pub source: Option<SourceRef>,
312
313    /// ID attribute value
314    pub id: Option<String>,
315}
316
317impl NotationDecl {
318    /// Create a new notation declaration
319    pub fn new(name: NameId, public: String) -> Self {
320        Self {
321            name,
322            target_namespace: None,
323            public,
324            system: None,
325            source: None,
326            id: None,
327        }
328    }
329}
330
331#[cfg(test)]
332mod tests {
333    use super::*;
334
335    #[test]
336    fn test_element_decl_global() {
337        let elem = ElementDecl::new_global(NameId(1), Some(NameId(2)));
338        assert!(elem.is_global());
339        assert!(!elem.is_local());
340        assert_eq!(elem.scope, DeclarationScope::Global);
341    }
342
343    #[test]
344    fn test_element_decl_local() {
345        let elem = ElementDecl::new_local(NameId(1), None);
346        assert!(elem.is_local());
347        assert!(!elem.is_global());
348        assert_eq!(elem.scope, DeclarationScope::Local);
349    }
350
351    #[test]
352    fn test_element_substitutable() {
353        let mut elem = ElementDecl::new_global(NameId(1), None);
354        assert!(elem.is_substitutable());
355
356        elem.is_abstract = true;
357        assert!(!elem.is_substitutable());
358    }
359
360    #[test]
361    fn test_attribute_decl_global() {
362        let attr = AttributeDecl::new_global(NameId(1), Some(NameId(2)));
363        assert!(attr.is_global());
364        assert!(!attr.is_local());
365    }
366
367    #[test]
368    fn test_attribute_decl_local() {
369        let attr = AttributeDecl::new_local(NameId(1), None);
370        assert!(attr.is_local());
371        assert!(!attr.is_global());
372    }
373
374    #[test]
375    fn test_value_constraint() {
376        let default_val = ValueConstraint::Default("foo".to_string());
377        assert!(!default_val.is_fixed());
378        assert_eq!(default_val.value(), "foo");
379
380        let fixed_val = ValueConstraint::Fixed("bar".to_string());
381        assert!(fixed_val.is_fixed());
382        assert_eq!(fixed_val.value(), "bar");
383    }
384
385    #[test]
386    fn test_attribute_value_constraint() {
387        let mut attr = AttributeDecl::new_local(NameId(1), None);
388        assert!(!attr.has_default());
389        assert!(!attr.has_fixed());
390
391        attr.value_constraint = Some(ValueConstraint::Default("test".to_string()));
392        assert!(attr.has_default());
393        assert!(!attr.has_fixed());
394
395        attr.value_constraint = Some(ValueConstraint::Fixed("test".to_string()));
396        assert!(!attr.has_default());
397        assert!(attr.has_fixed());
398    }
399
400    #[test]
401    fn test_notation_decl() {
402        let notation = NotationDecl::new(NameId(1), "http://example.com/public".to_string());
403        assert_eq!(notation.name, NameId(1));
404        assert_eq!(notation.public, "http://example.com/public");
405        assert!(notation.system.is_none());
406    }
407}