1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! XmlEventHandler implementation for streaming validation.
use std::sync::Arc;
use crate::error::{ErrorLevel, Result, StructuredError, ValidationErrorType};
use crate::event::{RawEvent, XmlEventHandler};
use super::OnePassSchemaValidator;
impl XmlEventHandler for OnePassSchemaValidator {
fn handle(&mut self, event: &RawEvent<'_>) -> Result<()> {
match event {
RawEvent::StartElement {
name,
prefix,
attributes,
namespace_decls,
line,
column,
} => {
self.current_line = *line;
self.current_column = *column;
self.state.push_namespaces(namespace_decls);
// Use the prefixed name to distinguish elements with the same
// local name but different namespaces (gml:boundedBy vs
// brid:boundedBy). Intern the qualified name once — its record
// links to the eagerly-interned local-name symbol, so both the
// qname and local symbols are obtained with a single probe.
let qname_sym = match prefix {
Some(p) if !p.is_empty() => {
self.qname_buf.clear();
self.qname_buf.push_str(p);
self.qname_buf.push(':');
self.qname_buf.push_str(name);
self.symbols.intern(&self.qname_buf)
}
_ => self.symbols.intern(name),
};
let name_sym = self.symbols.local(qname_sym);
let name_arc = Arc::clone(self.symbols.arc(name_sym));
let qname_arc = Arc::clone(self.symbols.arc(qname_sym));
// Resolve the element's namespace URI from the in-scope
// declarations (its prefix, or the default namespace). The
// URI drives wildcard namespace-set matching and
// namespace-aware element lookup — leaving it `None` made
// `##local` wildcards admit any prefixed element.
let namespace = self.state.resolve_element_namespace(prefix.as_deref());
self.state
.push_element_sym(Arc::clone(&qname_arc), namespace.clone(), qname_sym.0);
let attrs: smallvec::SmallVec<[(&str, &str); 8]> =
attributes.iter().map(|(k, v)| (*k, v.as_ref())).collect();
self.validate_element(
&name_arc,
prefix.as_deref(),
&qname_arc,
namespace.as_deref(),
&attrs,
);
}
RawEvent::EndElement { .. } => {
// The closing name is unused — the element being closed is the
// top of the state stack — so no interning is needed here.
self.validate_element_end();
self.state.pop_namespaces();
}
RawEvent::Text(text) => {
self.validate_text_content(text);
}
RawEvent::CData(text) => {
self.validate_text_content(text);
}
_ => {}
}
Ok(())
}
fn finish(&mut self) -> Result<()> {
// Final validation checks - report unclosed elements
while let Some(ctx) = self.state.pop_element() {
let error = StructuredError::new(
format!("element '{}' is not closed", ctx.name),
ValidationErrorType::UnclosedElement,
)
.with_node_name(ctx.name.as_ref())
.with_level(ErrorLevel::Error);
self.add_error(error);
}
// Resolve IDREF references against the IDs seen in the document
let unresolved: Vec<_> = self
.pending_idrefs
.drain(..)
.filter(|(idref, _, _)| !self.seen_ids.contains(idref))
.collect();
for (idref, line, column) in unresolved {
let mut error = StructuredError::new(
format!("IDREF '{}' does not match any ID in the document", idref),
ValidationErrorType::IdentityConstraint,
)
.with_level(ErrorLevel::Error);
if let Some(line) = line {
error = error.with_line(line);
}
if let Some(column) = column {
error = error.with_column(column);
}
self.add_error(error);
}
// Validate keyref constraints
if let Err(constraint_errors) = self.constraint_validator.validate_keyrefs() {
for err in constraint_errors {
let error =
StructuredError::new(err.to_string(), ValidationErrorType::IdentityConstraint)
.with_level(ErrorLevel::Error);
self.add_error(error);
}
}
Ok(())
}
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
self
}
}