Skip to main content

xsd_schema/parser/frames/
annotations.rs

1// ============================================================================
2// Annotation Frame
3// ============================================================================
4
5/// Frame for xs:annotation
6pub struct AnnotationFrame {
7    id: Option<String>,
8    items: Vec<AnnotationItem>,
9    source: Option<SourceRef>,
10    foreign_attributes: Vec<ForeignAttribute>,
11}
12
13impl AnnotationFrame {
14    pub fn new(
15        attrs: &AttributeMap,
16        name_table: &NameTable,
17        source: Option<SourceRef>,
18    ) -> SchemaResult<Self> {
19        let id = attrs
20            .get_value_by_name(name_table, "id")
21            .map(String::from);
22
23        Ok(Self {
24            id,
25            items: Vec::new(),
26            source,
27            foreign_attributes: Vec::new(),
28        })
29    }
30}
31
32impl Frame for AnnotationFrame {
33    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
34        matches!(local_name, xsd_names::APPINFO | xsd_names::DOCUMENTATION)
35    }
36
37    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
38        matches!(local_name, "id")
39    }
40
41    fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
42
43    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
44        match child {
45            FrameResult::AppInfo(appinfo) => {
46                self.items.push(AnnotationItem::AppInfo(appinfo));
47            }
48            FrameResult::Documentation(doc) => {
49                self.items.push(AnnotationItem::Documentation(doc));
50            }
51            _ => {
52                // Ignore other content in annotations
53            }
54        }
55        Ok(())
56    }
57
58    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
59        Ok(FrameResult::Annotation(Annotation {
60            id: self.id,
61            items: self.items,
62            source: self.source,
63            attributes: self.foreign_attributes,
64        }))
65    }
66
67    fn source(&self) -> Option<&SourceRef> {
68        self.source.as_ref()
69    }
70
71    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
72        self.foreign_attributes = attrs;
73    }
74}
75
76// ============================================================================
77// AppInfo Frame
78// ============================================================================
79
80/// Frame for xs:appinfo element
81pub struct AppinfoFrame {
82    source_attr: Option<String>,
83    start_span: Option<SourceRef>,
84    namespaces: NamespaceContextSnapshot,
85    foreign_attributes: Vec<ForeignAttribute>,
86}
87
88impl AppinfoFrame {
89    pub fn new(
90        attrs: &AttributeMap,
91        name_table: &NameTable,
92        source: Option<SourceRef>,
93    ) -> SchemaResult<Self> {
94        let source_attr = attrs
95            .get_value_by_name(name_table, "source")
96            .map(String::from);
97
98        Ok(Self {
99            source_attr,
100            start_span: source,
101            namespaces: NamespaceContextSnapshot::default(),
102            foreign_attributes: Vec::new(),
103        })
104    }
105}
106
107impl Frame for AppinfoFrame {
108    fn allows(&self, _local_name: &str, _name_table: &NameTable) -> bool {
109        // Appinfo allows any content (mixed content)
110        true
111    }
112
113    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
114        // Only 'source' attribute is standard, but allow foreign attrs
115        local_name == "source"
116    }
117
118    fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {
119        // Content is captured as raw XML, not parsed
120    }
121
122    fn attach(&mut self, _child: FrameResult) -> SchemaResult<()> {
123        // Any children are captured as part of mixed content
124        Ok(())
125    }
126
127    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
128        // Create XmlFragment from span
129        let fragment = if let Some(ref source) = self.start_span {
130            XmlFragment::new(source.doc_id, source.span)
131        } else {
132            XmlFragment::new(0, crate::parser::location::SourceSpan::new(0, 0))
133        };
134
135        let mut appinfo = AppInfoElement::new(fragment, self.namespaces);
136        appinfo.source = self.source_attr;
137        appinfo.attributes = self.foreign_attributes;
138        appinfo.source_ref = self.start_span;
139
140        Ok(FrameResult::AppInfo(appinfo))
141    }
142
143    fn source(&self) -> Option<&SourceRef> {
144        self.start_span.as_ref()
145    }
146
147    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
148        self.foreign_attributes = attrs;
149    }
150
151    fn accepts_text(&self) -> bool {
152        true
153    }
154
155    fn accepts_foreign_children(&self) -> bool {
156        true
157    }
158
159    fn on_text(&mut self, _text: &str) {
160        // Content is captured via XmlFragment span, not accumulated text
161    }
162
163    fn on_cdata(&mut self, _cdata: &str) {
164        // Content is captured via XmlFragment span, not accumulated text
165    }
166
167    fn set_namespaces(&mut self, namespaces: NamespaceContextSnapshot) {
168        self.namespaces = namespaces;
169    }
170}
171
172// ============================================================================
173// Documentation Frame
174// ============================================================================
175
176/// Frame for xs:documentation element
177pub struct DocumentationFrame {
178    source_attr: Option<String>,
179    lang: Option<String>,
180    start_span: Option<SourceRef>,
181    namespaces: NamespaceContextSnapshot,
182    foreign_attributes: Vec<ForeignAttribute>,
183}
184
185impl DocumentationFrame {
186    pub fn new(
187        attrs: &AttributeMap,
188        name_table: &NameTable,
189        source: Option<SourceRef>,
190    ) -> SchemaResult<Self> {
191        let source_attr = attrs
192            .get_value_by_name(name_table, "source")
193            .map(String::from);
194        let lang = attrs
195            .get_value_by_name(name_table, "lang")
196            .map(String::from);
197
198        Ok(Self {
199            source_attr,
200            lang,
201            start_span: source,
202            namespaces: NamespaceContextSnapshot::default(),
203            foreign_attributes: Vec::new(),
204        })
205    }
206}
207
208impl Frame for DocumentationFrame {
209    fn allows(&self, _local_name: &str, _name_table: &NameTable) -> bool {
210        // Documentation allows any content (mixed content)
211        true
212    }
213
214    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
215        // 'source' and xml:lang are standard attributes
216        matches!(local_name, "source" | "lang")
217    }
218
219    fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {
220        // Content is captured as raw XML, not parsed
221    }
222
223    fn attach(&mut self, _child: FrameResult) -> SchemaResult<()> {
224        // Any children are captured as part of mixed content
225        Ok(())
226    }
227
228    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
229        // Create XmlFragment from span
230        let fragment = if let Some(ref source) = self.start_span {
231            XmlFragment::new(source.doc_id, source.span)
232        } else {
233            XmlFragment::new(0, crate::parser::location::SourceSpan::new(0, 0))
234        };
235
236        let mut doc = DocumentationElement::new(fragment, self.namespaces);
237        doc.source = self.source_attr;
238        doc.lang = self.lang;
239        doc.attributes = self.foreign_attributes;
240        doc.source_ref = self.start_span;
241
242        Ok(FrameResult::Documentation(doc))
243    }
244
245    fn source(&self) -> Option<&SourceRef> {
246        self.start_span.as_ref()
247    }
248
249    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
250        self.foreign_attributes = attrs;
251    }
252
253    fn accepts_text(&self) -> bool {
254        true
255    }
256
257    fn accepts_foreign_children(&self) -> bool {
258        true
259    }
260
261    fn on_text(&mut self, _text: &str) {
262        // Content is captured via XmlFragment span, not accumulated text
263    }
264
265    fn on_cdata(&mut self, _cdata: &str) {
266        // Content is captured via XmlFragment span, not accumulated text
267    }
268
269    fn set_namespaces(&mut self, namespaces: NamespaceContextSnapshot) {
270        self.namespaces = namespaces;
271    }
272}
273