use std::collections::HashMap;
use super::wildcard::{
intersect_namespace_constraints, stricter_process_contents, union_namespace_constraints,
};
pub(super) type SubstitutionGroupMap =
HashMap<(Option<String>, String), Vec<(Option<String>, String)>>;
pub struct XsdValidator {
pub(super) elements: HashMap<(Option<String>, String), ElementDecl>,
pub(super) types: HashMap<(Option<String>, String), TypeDef>,
pub(super) global_attributes: HashMap<(Option<String>, String), AttributeDecl>,
pub(super) attribute_groups: HashMap<(Option<String>, String), AttributeGroupDef>,
pub(super) model_groups: HashMap<(Option<String>, String), ModelGroupDef>,
pub(super) target_namespace: Option<String>,
pub(super) block_default_extension: bool,
pub(super) block_default_restriction: bool,
pub(super) enforce_qname_length_facets: bool,
pub(super) substitution_groups: SubstitutionGroupMap,
}
#[derive(Debug, Clone)]
pub(crate) struct ElementDecl {
pub(super) name: String,
pub(super) namespace: Option<String>,
pub(super) type_ref: TypeRef,
#[allow(dead_code)]
pub(super) min_occurs: u64,
#[allow(dead_code)]
pub(super) max_occurs: MaxOccurs,
pub(super) nillable: bool,
pub(super) block_extension: bool,
pub(super) block_restriction: bool,
pub(super) is_ref: bool,
pub(super) substitution_group: Option<(Option<String>, String)>,
pub(super) is_abstract: bool,
pub(super) fixed: Option<String>,
pub(super) identity_constraints: Vec<IdentityConstraint>,
}
#[derive(Debug, Clone)]
pub(crate) struct IdentityConstraint {
pub(super) name: String,
pub(super) kind: IdentityConstraintKind,
pub(super) selector: String,
pub(super) fields: Vec<String>,
pub(super) refer: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum IdentityConstraintKind {
Key,
Unique,
KeyRef,
}
#[derive(Debug, Clone)]
pub(crate) enum TypeRef {
Named(Option<String>, String), Inline(Box<TypeDef>),
BuiltIn(BuiltInType),
}
#[derive(Debug, Clone)]
pub(crate) enum TypeDef {
Complex(ComplexTypeDef),
Simple(SimpleTypeDef),
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum NamespaceConstraint {
Any,
Other(Option<String>), Local,
TargetNamespace(Option<String>), List(Vec<String>),
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum ProcessContents {
Skip,
Lax,
Strict,
}
#[derive(Debug, Clone)]
pub(crate) struct AttributeWildcard {
pub(super) namespace_constraint: NamespaceConstraint,
pub(super) process_contents: ProcessContents,
}
impl AttributeWildcard {
pub(super) fn allows_namespace(&self, attr_ns: Option<&str>) -> bool {
match &self.namespace_constraint {
NamespaceConstraint::Any => true,
NamespaceConstraint::Other(target_ns) => {
match attr_ns {
None => false, Some(ns) => {
match target_ns {
Some(tns) => ns != tns,
None => true, }
}
}
}
NamespaceConstraint::Local => {
attr_ns.is_none()
}
NamespaceConstraint::TargetNamespace(target_ns) => {
attr_ns == target_ns.as_deref()
}
NamespaceConstraint::List(uris) => match attr_ns {
None => uris.iter().any(|u| u == "##local"),
Some(ns) => uris.iter().any(|u| u == ns),
},
}
}
pub(super) fn intersect(&self, other: &AttributeWildcard) -> Option<AttributeWildcard> {
let ns = intersect_namespace_constraints(
&self.namespace_constraint,
&other.namespace_constraint,
)?;
let pc = stricter_process_contents(&self.process_contents, &other.process_contents);
Some(AttributeWildcard {
namespace_constraint: ns,
process_contents: pc,
})
}
pub(super) fn union(&self, other: &AttributeWildcard) -> AttributeWildcard {
let ns =
union_namespace_constraints(&self.namespace_constraint, &other.namespace_constraint);
AttributeWildcard {
namespace_constraint: ns,
process_contents: other.process_contents.clone(),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct AttributeGroupDef {
pub(super) attributes: Vec<AttributeDecl>,
pub(super) wildcard: Option<AttributeWildcard>,
}
#[derive(Debug, Clone)]
pub(crate) struct ModelGroupDef {
pub(super) content: ContentModel,
}
#[derive(Debug, Clone)]
pub(crate) struct ComplexTypeDef {
pub(super) name: Option<String>,
pub(super) content: ContentModel,
pub(super) attributes: Vec<AttributeDecl>,
pub(super) mixed: bool,
pub(super) attribute_wildcard: Option<AttributeWildcard>,
pub(super) base_type: Option<(Option<String>, String)>,
pub(super) derived_by_extension: Option<bool>,
pub(super) block_extension: bool,
pub(super) block_restriction: bool,
pub(super) group_ref: Option<(Option<String>, String)>,
pub(super) attribute_group_refs: Vec<(Option<String>, String)>,
}
#[derive(Debug, Clone)]
pub(crate) enum ContentModel {
Empty,
Sequence(Vec<Particle>, u64, MaxOccurs), Choice(Vec<Particle>, u64, MaxOccurs), All(Vec<Particle>),
SimpleContent(Box<TypeRef>),
#[allow(dead_code)]
Any,
}
#[derive(Debug, Clone)]
pub(crate) struct Particle {
pub(super) kind: ParticleKind,
pub(super) min_occurs: u64,
pub(super) max_occurs: MaxOccurs,
}
#[derive(Debug, Clone)]
pub(crate) enum ParticleKind {
Element(ElementDecl),
Sequence(Vec<Particle>),
Choice(Vec<Particle>),
Any {
namespace_constraint: NamespaceConstraint,
process_contents: ProcessContents,
},
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum MaxOccurs {
Bounded(u64),
Unbounded,
}
#[derive(Debug, Clone)]
pub(crate) struct AttributeDecl {
pub(super) name: String,
pub(super) type_ref: TypeRef,
pub(super) required: bool,
#[allow(dead_code)]
pub(super) default: Option<String>,
pub(super) prohibited: bool,
}
#[derive(Debug, Clone)]
pub(crate) struct SimpleTypeDef {
pub(super) name: Option<String>,
pub(super) base: BuiltInType,
pub(super) facets: Vec<Facet>,
pub(super) is_list: bool,
pub(super) item_type: Option<BuiltInType>,
pub(super) item_facets: Vec<Facet>,
pub(super) _base_type_local: Option<String>,
pub(super) _item_type_local: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
pub(crate) enum BuiltInType {
String,
Boolean,
Decimal,
Float,
Double,
Integer,
Long,
Int,
Short,
Byte,
NonNegativeInteger,
PositiveInteger,
NonPositiveInteger,
NegativeInteger,
UnsignedLong,
UnsignedInt,
UnsignedShort,
UnsignedByte,
DateTime,
Date,
Time,
Duration,
GYear,
GYearMonth,
GMonth,
GMonthDay,
GDay,
HexBinary,
Base64Binary,
AnyURI,
QName,
NormalizedString,
Token,
Language,
Name,
NCName,
ID,
IDREF,
IDREFS,
NMTOKEN,
NMTOKENS,
NOTATION,
ENTITY,
ENTITIES,
AnyType,
AnySimpleType,
}
#[derive(Debug, Clone)]
pub(crate) enum Facet {
MinLength(usize),
MaxLength(usize),
Length(usize),
Pattern(String),
Enumeration(Vec<String>),
MinInclusive(String),
MaxInclusive(String),
MinExclusive(String),
MaxExclusive(String),
TotalDigits(usize),
FractionDigits(usize),
WhiteSpace(#[allow(dead_code)] WhiteSpaceHandling),
}
#[derive(Debug, Clone)]
pub(crate) enum WhiteSpaceHandling {
Preserve,
Replace,
Collapse,
}