use std::collections::HashMap;
use std::sync::Arc;
use super::types::{ComplexType, SimpleType};
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
pub enum SchemaVersion {
#[default]
Xsd10,
Xsd11,
Auto,
}
#[derive(Default, Clone, Debug)]
pub struct SchemaOptions {
pub version: SchemaVersion,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QName {
pub namespace: Option<Arc<str>>,
pub local: Arc<str>,
}
impl QName {
pub fn new(ns: Option<&str>, local: &str) -> Self {
Self {
namespace: ns.map(Arc::from),
local: Arc::from(local),
}
}
pub const XSD_NS: &'static str = "http://www.w3.org/2001/XMLSchema";
pub fn xsd(local: &str) -> Self {
Self::new(Some(Self::XSD_NS), local)
}
}
impl std::fmt::Display for QName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.namespace {
Some(ns) => write!(f, "{{{ns}}}{}", self.local),
None => f.write_str(&self.local),
}
}
}
#[derive(Debug)]
pub struct ElementDecl {
pub name: QName,
pub type_def: TypeRef,
pub nillable: bool,
pub default: Option<String>,
pub fixed: Option<String>,
pub abstract_: bool,
pub substitution_group: Option<QName>,
pub block: BlockSet,
pub final_: BlockSet,
pub identity: Vec<super::identity::IdentityConstraint>,
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct BlockSet: u8 {
const RESTRICTION = 0b00001;
const EXTENSION = 0b00010;
const SUBSTITUTION = 0b00100;
const LIST = 0b01000;
const UNION = 0b10000;
}
}
#[derive(Debug)]
pub struct AttributeDecl {
pub name: QName,
pub type_def: Arc<SimpleType>,
pub default: Option<String>,
pub fixed: Option<String>,
pub inheritable: bool,
}
#[derive(Debug, Clone)]
pub struct AttributeUse {
pub use_kind: AttributeUseKind,
pub decl: Arc<AttributeDecl>,
pub default: Option<String>,
pub fixed: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AttributeUseKind { Required, Optional, Prohibited }
#[derive(Debug, Clone)]
pub struct Assertion {
pub test: String,
pub namespaces: Vec<(Option<String>, String)>,
pub xpath_default_namespace: Option<String>,
}
#[derive(Debug, Clone)]
pub enum ContentModel {
Empty,
Simple(Arc<SimpleType>),
Complex { root: Particle, mixed: bool },
}
#[derive(Debug, Clone)]
pub struct Particle {
pub min_occurs: u32,
pub max_occurs: MaxOccurs,
pub term: Term,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MaxOccurs { Bounded(u32), Unbounded }
impl MaxOccurs {
pub fn allows(self, n: u32) -> bool {
match self {
MaxOccurs::Bounded(m) => n <= m,
MaxOccurs::Unbounded => true,
}
}
}
#[derive(Debug, Clone)]
pub enum Term {
Element(Arc<ElementDecl>),
Group {
kind: GroupKind,
particles: Arc<[Particle]>,
},
Wildcard(Wildcard),
GroupRef(QName),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GroupKind { Sequence, Choice, All }
#[derive(Debug, Clone)]
pub struct Wildcard {
pub namespaces: NamespaceConstraint,
pub process_contents: ProcessContents,
pub not_qnames: Vec<QName>,
pub not_namespaces: Vec<Option<Arc<str>>>,
pub not_qname_defined: bool,
pub not_qname_defined_sibling: bool,
}
#[derive(Debug, Clone)]
pub enum NamespaceConstraint {
Any,
Other,
List(Vec<Option<Arc<str>>>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProcessContents { Strict, Lax, Skip }
#[derive(Debug)]
pub struct NotationDecl {
pub name: QName,
pub public_id: Option<String>,
pub system_id: Option<String>,
}
#[derive(Debug, Clone)]
pub enum TypeRef {
Simple(Arc<SimpleType>),
Complex(Arc<ComplexType>),
}
#[derive(Clone)]
pub struct Schema {
inner: Arc<SchemaInner>,
}
impl std::fmt::Debug for Schema {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Schema")
.field("target_namespace", &self.inner.target_namespace)
.field("elements", &self.inner.elements.keys().collect::<Vec<_>>())
.field("types", &self.inner.types.keys().collect::<Vec<_>>())
.field("attributes", &self.inner.attributes.keys().collect::<Vec<_>>())
.finish()
}
}
#[allow(dead_code)] pub(crate) struct SchemaInner {
pub target_namespace: Option<Arc<str>>,
pub elements: HashMap<QName, Arc<ElementDecl>>,
pub attributes: HashMap<QName, Arc<AttributeDecl>>,
pub types: HashMap<QName, TypeRef>,
pub attribute_groups: HashMap<QName, Arc<AttributeGroup>>,
pub model_groups: HashMap<QName, Arc<ModelGroup>>,
pub notations: HashMap<QName, Arc<NotationDecl>>,
pub substitutions: HashMap<QName, Vec<Arc<ElementDecl>>>,
}
impl Schema {
pub(crate) fn from_inner(inner: SchemaInner) -> Self {
Self { inner: Arc::new(inner) }
}
pub fn element(&self, name: &QName) -> Option<&Arc<ElementDecl>> {
self.inner.elements.get(name)
}
pub fn attribute(&self, name: &QName) -> Option<&Arc<AttributeDecl>> {
self.inner.attributes.get(name)
}
pub fn type_def(&self, name: &QName) -> Option<&TypeRef> {
self.inner.types.get(name)
}
pub fn target_namespace(&self) -> Option<&str> {
self.inner.target_namespace.as_deref()
}
pub fn elements(&self) -> impl Iterator<Item = (&QName, &Arc<ElementDecl>)> {
self.inner.elements.iter()
}
pub fn types(&self) -> impl Iterator<Item = (&QName, &TypeRef)> {
self.inner.types.iter()
}
pub fn substitutes_for(&self, head: &QName) -> &[Arc<ElementDecl>] {
self.inner.substitutions.get(head).map(|v| v.as_slice()).unwrap_or(&[])
}
}
#[derive(Debug)]
pub struct AttributeGroup {
pub name: QName,
pub attributes: Vec<AttributeUse>,
pub any: Option<Wildcard>,
}
#[derive(Debug)]
pub struct ModelGroup {
pub name: QName,
pub particle: Particle,
}