mod content;
mod event_handler;
mod lookup;
mod occurrence;
use std::io::BufRead;
use std::sync::Arc;
use crate::error::{Result, StructuredError, ValidationErrorType};
use crate::event::StreamingParser;
use crate::schema::types::CompiledSchema;
use crate::schema::xsd::constraints::ConstraintValidator;
use super::ValidationMode;
use super::state::ValidationState;
#[derive(Debug, Clone, Default)]
pub struct ValidationOptions {
pub skip_min_occurs: bool,
pub skip_max_occurs: bool,
pub skip_substitution_groups: bool,
}
pub struct OnePassSchemaValidator {
pub(crate) schema: Arc<CompiledSchema>,
pub(crate) state: ValidationState,
pub(crate) errors: Vec<StructuredError>,
pub(crate) current_line: Option<usize>,
pub(crate) current_column: Option<usize>,
pub(crate) constraint_validator: ConstraintValidator,
pub(crate) mode: ValidationMode,
pub(crate) max_errors: usize,
pub(crate) options: ValidationOptions,
}
impl OnePassSchemaValidator {
pub fn new(schema: Arc<CompiledSchema>) -> Self {
Self {
schema,
state: ValidationState::new(),
errors: Vec::new(),
current_line: None,
current_column: Some(1),
constraint_validator: ConstraintValidator::new(),
mode: ValidationMode::Strict,
max_errors: 0,
options: ValidationOptions::default(),
}
}
#[deprecated(
since = "0.3.0",
note = "use OnePassSchemaValidator::new(schema).set_mode(mode) instead"
)]
pub fn with_mode(schema: Arc<CompiledSchema>, mode: ValidationMode) -> Self {
Self {
mode,
..Self::new(schema)
}
}
#[deprecated(
since = "0.3.0",
note = "use OnePassSchemaValidator::new(schema).set_options(options) instead"
)]
pub fn with_options(schema: Arc<CompiledSchema>, options: ValidationOptions) -> Self {
Self {
options,
..Self::new(schema)
}
}
pub fn set_mode(mut self, mode: ValidationMode) -> Self {
self.mode = mode;
self
}
pub fn set_options(&mut self, options: ValidationOptions) {
self.options = options;
}
pub fn options(&self) -> &ValidationOptions {
&self.options
}
pub fn with_max_errors(mut self, max: usize) -> Self {
self.max_errors = max;
self
}
pub fn set_max_errors(&mut self, max: usize) {
self.max_errors = max;
}
pub fn validate<R: BufRead>(self, reader: R) -> Result<Vec<StructuredError>> {
let mut parser = StreamingParser::new(reader);
parser.add_handler(Box::new(self));
parser.parse()?;
let handlers = parser.into_handlers();
for handler in handlers {
if let Ok(validator) = handler.as_any().downcast::<OnePassSchemaValidator>() {
return Ok(validator.into_errors());
}
}
Ok(Vec::new())
}
pub fn errors(&self) -> &[StructuredError] {
&self.errors
}
pub fn errors_only(&self) -> Vec<&StructuredError> {
self.errors.iter().filter(|e| e.is_error()).collect()
}
pub fn warnings(&self) -> Vec<&StructuredError> {
self.errors.iter().filter(|e| e.is_warning()).collect()
}
pub fn into_errors(self) -> Vec<StructuredError> {
self.errors
}
pub fn is_valid(&self) -> bool {
!self.errors.iter().any(|e| e.is_error())
}
pub fn is_clean(&self) -> bool {
self.errors.is_empty()
}
pub fn error_count(&self) -> usize {
self.errors.iter().filter(|e| e.is_error()).count()
}
pub fn warning_count(&self) -> usize {
self.errors.iter().filter(|e| e.is_warning()).count()
}
pub(crate) fn should_collect_more(&self) -> bool {
self.max_errors == 0 || self.errors.len() < self.max_errors
}
pub(crate) fn add_error(&mut self, error: StructuredError) {
if self.should_collect_more() {
self.errors.push(error);
}
}
pub(crate) fn make_error(
&self,
error_type: ValidationErrorType,
message: impl Into<String>,
) -> StructuredError {
let mut error = StructuredError::new(message, error_type);
if let Some(line) = self.current_line {
error = error.with_line(line);
}
if let Some(column) = self.current_column {
error = error.with_column(column);
}
error = error.with_element_path(self.state.element_path());
error
}
}
pub type StreamValidator = OnePassSchemaValidator;
#[cfg(test)]
mod tests;