use std::sync::Arc;
use crate::schema::types::{
ComplexType, ContentModel, ContentModelType, ElementDef, FlattenedChildren, TypeDef,
};
use super::DomSchemaValidator;
impl DomSchemaValidator {
pub(crate) fn lookup_element(
&self,
name: &str,
prefix: Option<&str>,
namespace_uri: Option<&str>,
) -> Option<&ElementDef> {
if let Some(p) = prefix
&& !p.is_empty()
{
let qname = format!("{}:{}", p, name);
if let Some(elem) = self.schema.get_element(&qname) {
return Some(elem);
}
}
if let Some(ns) = namespace_uri
&& let Some(elem) = self.schema.get_element_by_ns(ns, name)
{
return Some(elem);
}
if let Some(elem) = self.schema.get_element(name) {
return Some(elem);
}
None
}
pub(crate) fn get_flattened_children_for_element(
&self,
elem: &ElementDef,
) -> Option<Arc<FlattenedChildren>> {
if let Some(ref type_ref) = elem.type_ref {
if let Some(ns_name) = self.schema.resolve_type_ref_to_ns(type_ref)
&& let Some(cached) = self.schema.ns_type_children_cache.get(&ns_name)
{
return Some(Arc::clone(cached));
}
if let Some(cached) = self.schema.type_children_cache.get(type_ref) {
return Some(Arc::clone(cached));
}
if let Some((_prefix, local)) = type_ref.split_once(':') {
if let Some(cached) = self.schema.type_children_cache.get(local) {
return Some(Arc::clone(cached));
}
}
if let Some(TypeDef::Complex(complex)) = self.schema.get_type(type_ref) {
return Some(Arc::new(self.compute_flattened_children(complex)));
}
}
if let Some(ref inline_type) = elem.inline_type {
if let TypeDef::Complex(complex) = inline_type {
return Some(Arc::new(self.compute_flattened_children(complex)));
}
}
None
}
pub(crate) fn compute_flattened_children(&self, complex: &ComplexType) -> FlattenedChildren {
let content_model_type = match &complex.content {
ContentModel::Sequence(_) => ContentModelType::Sequence,
ContentModel::Choice(_) => ContentModelType::Choice,
ContentModel::All(_) => ContentModelType::All,
ContentModel::ComplexExtension { .. } => ContentModelType::Sequence,
ContentModel::Empty => ContentModelType::Empty,
ContentModel::SimpleContent { .. } => ContentModelType::Empty,
ContentModel::Any { .. } => ContentModelType::Sequence,
};
let mut flattened = FlattenedChildren::with_content_model(content_model_type);
let mut visited = std::collections::HashSet::new();
let elements = self.collect_elements_with_inheritance(complex, &mut visited);
let mut ordered: Vec<String> = Vec::with_capacity(elements.len());
for elem in &elements {
flattened
.constraints
.insert(elem.name.clone(), (elem.min_occurs, elem.max_occurs));
ordered.push(elem.name.clone());
}
flattened.ordered_elements = std::sync::Arc::from(ordered);
flattened.wildcard =
crate::schema::xsd::compiler::inherited_wildcard(complex, &self.schema);
flattened
}
pub(crate) fn collect_elements_with_inheritance(
&self,
complex: &ComplexType,
visited: &mut std::collections::HashSet<String>,
) -> Vec<ElementDef> {
let mut elements = Vec::new();
match &complex.content {
ContentModel::Sequence(elems)
| ContentModel::Choice(elems)
| ContentModel::All(elems) => {
elements.extend(elems.iter().cloned());
}
ContentModel::ComplexExtension {
base_type,
elements: ext_elements,
} => {
if !visited.contains(base_type.as_str()) {
visited.insert(base_type.clone());
if let Some(TypeDef::Complex(base_complex)) =
self.schema.get_type(base_type.as_str())
{
let base_elements =
self.collect_elements_with_inheritance(base_complex, visited);
elements.extend(base_elements);
}
}
elements.extend(ext_elements.iter().cloned());
}
_ => {}
}
elements
}
}