use crate::error::{SchemaError, SchemaResult};
use crate::ids::*;
use crate::parser::frames::SimpleTypeVariety;
use crate::parser::frames::{QNameRef, TypeRefResult};
use crate::parser::location::SourceRef;
use crate::schema::composition::ComponentKind;
use crate::schema::SchemaSet;
pub(crate) fn check_namespace_visible_ns(
schema_set: &SchemaSet,
namespace: Option<NameId>,
local_name: NameId,
source: Option<&SourceRef>,
kind_label: &str,
) -> SchemaResult<()> {
let Some(source) = source else { return Ok(()) };
let Some(doc) = schema_set.documents.get(source.doc_id as usize) else {
return Ok(());
};
if doc.can_see_namespace(namespace, &schema_set.name_table) {
return Ok(());
}
let location = schema_set.source_maps.locate(source);
let qname_str = format_resolved_qname(&schema_set.name_table, namespace, local_name);
let ns_label = match namespace {
Some(ns) => format!("'{}'", schema_set.name_table.resolve_ref(ns)),
None => "the absent namespace".to_string(),
};
Err(SchemaError::structural(
"src-resolve",
format!(
"{} reference '{}' to namespace {} is not <xs:import>-ed by schema document '{}'",
kind_label, qname_str, ns_label, doc.base_uri,
),
location,
))
}
pub(crate) fn check_namespace_visible(
schema_set: &SchemaSet,
qname: &QNameRef,
source: Option<&SourceRef>,
kind_label: &str,
) -> SchemaResult<()> {
check_namespace_visible_ns(schema_set, qname.namespace, qname.local_name, source, kind_label)
}
pub struct ReferenceResolver<'a> {
schema_set: &'a SchemaSet,
}
impl<'a> ReferenceResolver<'a> {
pub fn new(schema_set: &'a SchemaSet) -> Self {
Self { schema_set }
}
pub fn resolve_type_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<TypeKey> {
let namespace = qname.namespace;
if let Some(type_key) = self
.schema_set
.get_built_in_type_by_qname(namespace, qname.local_name)
{
return Ok(type_key);
}
check_namespace_visible(self.schema_set, qname, source, "Type")?;
if let Some(type_key) = self.schema_set.lookup_type(namespace, qname.local_name) {
return Ok(type_key);
}
let location = source.and_then(|s| self.schema_set.source_maps.locate(s));
Err(SchemaError::structural(
"src-resolve",
format_type_not_found_message(self.schema_set, qname, "Type"),
location,
))
}
pub fn try_resolve_type_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<Option<TypeKey>> {
if let Some(type_key) = self
.schema_set
.get_built_in_type_by_qname(qname.namespace, qname.local_name)
{
return Ok(Some(type_key));
}
check_namespace_visible(self.schema_set, qname, source, "Type")?;
Ok(self.schema_set.lookup_type(qname.namespace, qname.local_name))
}
pub fn try_resolve_element_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<Option<ElementKey>> {
check_namespace_visible(self.schema_set, qname, source, "Element")?;
Ok(self
.schema_set
.lookup_element(qname.namespace, qname.local_name))
}
pub fn resolve_type_ref_result(
&self,
type_ref: &TypeRefResult,
source: Option<&SourceRef>,
) -> SchemaResult<Option<TypeKey>> {
match type_ref {
TypeRefResult::QName(qname) => Ok(Some(self.resolve_type_ref(qname, source)?)),
TypeRefResult::Inline(_) => {
Ok(None)
}
}
}
fn resolve_ref<K: Copy>(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
kind_label: &str,
component_kind: ComponentKind,
lookup: impl FnOnce(&SchemaSet, Option<NameId>, NameId) -> Option<K>,
) -> SchemaResult<K> {
check_namespace_visible(self.schema_set, qname, source, kind_label)?;
if let Some(key) = lookup(self.schema_set, qname.namespace, qname.local_name) {
return Ok(key);
}
let location = source.and_then(|s| self.schema_set.source_maps.locate(s));
let name_str = self.format_qname(qname);
let note = self.schema_set.format_provenance_note(
component_kind,
qname.namespace,
qname.local_name,
);
Err(SchemaError::structural(
"src-resolve",
format!("{} '{}' not found{}", kind_label, name_str, note),
location,
))
}
pub fn resolve_element_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<ElementKey> {
self.resolve_ref(
qname,
source,
"Element",
ComponentKind::Element,
SchemaSet::lookup_element,
)
}
pub fn resolve_attribute_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<AttributeKey> {
self.resolve_ref(
qname,
source,
"Attribute",
ComponentKind::Attribute,
SchemaSet::lookup_attribute,
)
}
pub fn resolve_group_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<ModelGroupKey> {
self.resolve_ref(
qname,
source,
"Group",
ComponentKind::ModelGroup,
SchemaSet::lookup_model_group,
)
}
pub fn resolve_attribute_group_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<AttributeGroupKey> {
self.resolve_ref(
qname,
source,
"Attribute group",
ComponentKind::AttributeGroup,
SchemaSet::lookup_attribute_group,
)
}
pub fn resolve_notation_ref(
&self,
qname: &QNameRef,
source: Option<&SourceRef>,
) -> SchemaResult<NotationKey> {
self.resolve_ref(
qname,
source,
"Notation",
ComponentKind::Notation,
SchemaSet::lookup_notation,
)
}
fn format_qname(&self, qname: &QNameRef) -> String {
format_resolved_qname(
&self.schema_set.name_table,
qname.namespace,
qname.local_name,
)
}
}
pub(crate) fn format_resolved_qname(
name_table: &crate::namespace::NameTable,
namespace: Option<crate::ids::NameId>,
local_name: crate::ids::NameId,
) -> String {
let local = name_table.resolve(local_name);
if let Some(ns_id) = namespace {
let ns = name_table.resolve(ns_id);
if ns.is_empty() {
local
} else {
format!("{{{}}}{}", ns, local)
}
} else {
local
}
}
#[derive(Debug, Default)]
pub struct ResolvedReferences {
pub resolved_type: Option<TypeKey>,
pub resolved_ref: Option<ElementKey>,
pub resolved_substitution_groups: Vec<ElementKey>,
pub resolved_attr_ref: Option<AttributeKey>,
pub resolved_base_type: Option<TypeKey>,
pub resolved_item_type: Option<TypeKey>,
pub resolved_member_types: Vec<TypeKey>,
pub resolved_attribute_groups: Vec<AttributeGroupKey>,
pub resolved_group_ref: Option<ModelGroupKey>,
}
#[derive(Debug, Default)]
pub struct ResolutionStats {
pub types_resolved: usize,
pub elements_resolved: usize,
pub attributes_resolved: usize,
pub groups_resolved: usize,
pub attribute_groups_resolved: usize,
pub notations_resolved: usize,
pub errors: usize,
}
fn drain_pending_ic_refs_for(
schema_set: &mut SchemaSet,
key: ElementKey,
defer_failures: bool,
errors: &mut Vec<SchemaError>,
) {
let pending = std::mem::take(&mut schema_set.arenas.elements[key].pending_ic_refs);
if pending.is_empty() {
return;
}
let target_ns = schema_set.arenas.elements[key].target_namespace;
let mut still_pending = Vec::new();
for (kind, ref_name, source) in pending {
match crate::schema::inline::resolve_ic_ref(
kind,
&ref_name,
source.as_ref(),
target_ns,
schema_set,
) {
Ok(target_key) => {
schema_set.arenas.elements[key]
.identity_constraints
.push(target_key);
}
Err(e) => {
if defer_failures {
still_pending.push((kind, ref_name, source));
} else {
errors.push(e);
}
}
}
}
if !still_pending.is_empty() {
schema_set.arenas.elements[key].pending_ic_refs = still_pending;
}
}
pub fn finalize_pending_ic_refs(schema_set: &mut SchemaSet) -> SchemaResult<()> {
let element_keys: Vec<ElementKey> = schema_set.arenas.elements.keys().collect();
let mut errors: Vec<SchemaError> = Vec::new();
for key in element_keys {
drain_pending_ic_refs_for(schema_set, key, false, &mut errors);
}
if let Some(first) = errors.into_iter().next() {
return Err(first);
}
Ok(())
}
pub fn resolve_all_references(schema_set: &mut SchemaSet) -> SchemaResult<ResolutionStats> {
let mut stats = ResolutionStats::default();
let mut errors: Vec<SchemaError> = Vec::new();
let element_keys: Vec<ElementKey> = schema_set.arenas.elements.keys().collect();
let attribute_keys: Vec<AttributeKey> = schema_set.arenas.attributes.keys().collect();
let simple_type_keys: Vec<SimpleTypeKey> = schema_set.arenas.simple_types.keys().collect();
let complex_type_keys: Vec<ComplexTypeKey> = schema_set.arenas.complex_types.keys().collect();
let model_group_keys: Vec<ModelGroupKey> = schema_set.arenas.model_groups.keys().collect();
let attribute_group_keys: Vec<AttributeGroupKey> =
schema_set.arenas.attribute_groups.keys().collect();
for key in &element_keys {
if let Err(e) = resolve_element_references(schema_set, *key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
if errors.is_empty() {
loop {
let mut changed = false;
for &key in &element_keys {
let (needs_type, subst_groups) = {
let elem = schema_set.arenas.elements.get(key).unwrap();
(
elem.resolved_type.is_none()
&& elem.resolved_ref.is_none()
&& elem.deferred_type_error.is_none()
&& !elem.resolved_substitution_groups.is_empty(),
elem.resolved_substitution_groups.clone(),
)
};
if needs_type {
for &head_key in &subst_groups {
if let Some(head_type) = schema_set
.arenas
.elements
.get(head_key)
.and_then(|h| h.resolved_type)
{
let elem = schema_set.arenas.elements.get_mut(key).unwrap();
assign_element_type(elem, head_type);
changed = true;
break;
}
}
}
}
if !changed {
break;
}
}
for &key in &element_keys {
let needs_deferred = {
let elem = schema_set.arenas.elements.get(key).unwrap();
elem.resolved_type.is_none()
&& elem.resolved_ref.is_none()
&& elem.deferred_type_error.is_none()
&& !elem.resolved_substitution_groups.is_empty()
};
if !needs_deferred {
continue;
}
let inherited = {
let elem = schema_set.arenas.elements.get(key).unwrap();
elem.resolved_substitution_groups
.iter()
.find_map(|&head_key| {
schema_set
.arenas
.elements
.get(head_key)
.and_then(|h| h.deferred_type_error.clone())
})
};
if let Some(deferred) = inherited {
if let Some(elem) = schema_set.arenas.elements.get_mut(key) {
elem.deferred_type_error = Some(deferred);
}
}
}
let any_type = TypeKey::Complex(schema_set.any_type_key());
for &key in &element_keys {
if let Some(elem) = schema_set.arenas.elements.get_mut(key) {
if elem.resolved_type.is_none()
&& elem.resolved_ref.is_none()
&& elem.deferred_type_error.is_none()
{
assign_element_type(elem, any_type);
}
}
}
}
for &key in &element_keys {
drain_pending_ic_refs_for(schema_set, key, true, &mut errors);
}
for key in attribute_keys {
if let Err(e) = resolve_attribute_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
for key in simple_type_keys.clone() {
if let Err(e) = resolve_simple_type_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
for key in simple_type_keys {
if let Err(e) = resolve_simple_type_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
for &key in &complex_type_keys {
if let Err(e) = resolve_complex_type_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
for key in model_group_keys {
if let Err(e) = resolve_model_group_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
for key in attribute_group_keys {
if let Err(e) = resolve_attribute_group_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
let notation_keys: Vec<NotationKey> = schema_set.arenas.notations.keys().collect();
for key in notation_keys {
if let Err(e) = resolve_notation_references(schema_set, key, &mut stats) {
errors.push(e);
stats.errors += 1;
}
}
let mut doc_default_attr_groups: Vec<Option<AttributeGroupKey>> =
Vec::with_capacity(schema_set.documents.len());
for doc in &schema_set.documents {
if let Some(ref qname) = doc.default_attributes {
if let Err(e) = check_namespace_visible_ns(
schema_set,
qname.namespace_uri,
qname.local_name,
doc.source.as_ref(),
"Attribute group",
) {
errors.push(e);
stats.errors += 1;
doc_default_attr_groups.push(None);
continue;
}
if let Some(key) =
schema_set.lookup_attribute_group(qname.namespace_uri, qname.local_name)
{
doc_default_attr_groups.push(Some(key));
stats.attribute_groups_resolved += 1;
} else {
let location = schema_set.locate(doc.source.as_ref());
let name_str = format_resolved_qname(
&schema_set.name_table,
qname.namespace_uri,
qname.local_name,
);
errors.push(SchemaError::structural(
"src-resolve",
format!("Attribute group '{}' not found", name_str),
location,
));
stats.errors += 1;
doc_default_attr_groups.push(None);
}
} else {
doc_default_attr_groups.push(None);
}
}
for &key in &complex_type_keys {
let doc_id = {
let type_def = match schema_set.arenas.complex_types.get(key) {
Some(td) => td,
None => continue,
};
if !type_def.default_attributes_apply {
continue;
}
match type_def.source.as_ref() {
Some(src) => src.defaults_doc(),
None => continue, }
};
if let Some(Some(group_key)) = doc_default_attr_groups.get(doc_id as usize) {
let group_key = *group_key;
let type_def = schema_set.arenas.complex_types.get_mut(key).unwrap();
if !type_def.resolved_attribute_groups.contains(&group_key) {
type_def.resolved_attribute_groups.push(group_key);
}
}
}
if let Err(e) = validate_particle_qname_visibility(schema_set) {
errors.push(e);
stats.errors += 1;
}
if let Some(first_error) = errors.into_iter().next() {
return Err(first_error);
}
Ok(stats)
}
fn validate_particle_qname_visibility(schema_set: &SchemaSet) -> SchemaResult<()> {
use crate::parser::frames::{ParticleResult, ParticleTerm};
fn visit(
schema_set: &SchemaSet,
particles: &[ParticleResult],
depth: usize,
) -> SchemaResult<()> {
if depth > 64 {
return Ok(());
}
for particle in particles {
match &particle.term {
ParticleTerm::Element(elem) => {
let src = elem.source.as_ref().or(particle.source.as_ref());
if let Some(ref_qn) = &elem.ref_name {
check_namespace_visible(schema_set, ref_qn, src, "Element")?;
}
if let Some(TypeRefResult::QName(qname)) = &elem.type_ref {
check_namespace_visible(schema_set, qname, src, "Type")?;
}
}
ParticleTerm::Group(group_def) => {
if let Some(ref_qn) = &group_def.ref_name {
check_namespace_visible(
schema_set,
ref_qn,
particle.source.as_ref(),
"Group",
)?;
}
visit(schema_set, &group_def.particles, depth + 1)?;
}
ParticleTerm::Any(_) => {}
}
}
Ok(())
}
for (_, ct) in schema_set.arenas.complex_types.iter() {
if let crate::parser::frames::ComplexContentResult::Complex(content) = &ct.content {
if let Some(particle) = &content.particle {
visit(schema_set, std::slice::from_ref(particle), 0)?;
}
}
}
Ok(())
}
fn assign_element_type(elem: &mut crate::arenas::ElementDeclData, type_key: TypeKey) {
elem.resolved_type = Some(type_key);
#[cfg(feature = "xsd11")]
for alt in &mut elem.alternatives {
if alt.resolved_type.is_none() && alt.type_ref.is_none() {
alt.resolved_type = Some(type_key);
}
}
}
fn resolve_element_references(
schema_set: &mut SchemaSet,
key: ElementKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
let (type_qname, ref_name, substitution_groups, source, already_resolved_type) = {
let elem = schema_set
.arenas
.elements
.get(key)
.ok_or_else(|| SchemaError::internal("Element not found in arena"))?;
let type_qname = match &elem.type_ref {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
(
type_qname,
elem.ref_name.clone(),
elem.substitution_group.clone(),
elem.source.clone(),
elem.resolved_type, )
};
let resolver = ReferenceResolver::new(schema_set);
let lazy_src_resolve = schema_set.is_xsd10();
let mut deferred_type_error: Option<crate::arenas::DeferredSrcResolve> = None;
let mut resolved_type = if already_resolved_type.is_some() {
already_resolved_type
} else if let Some(ref qname) = type_qname {
if lazy_src_resolve {
match resolver.try_resolve_type_ref(qname, source.as_ref())? {
Some(type_key) => {
stats.types_resolved += 1;
Some(type_key)
}
None => {
deferred_type_error = Some(build_deferred_type_resolve(
schema_set,
qname,
source.as_ref(),
"Type",
));
None
}
}
} else {
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
}
} else {
None
};
if resolved_type.is_none()
&& deferred_type_error.is_none()
&& ref_name.is_none()
&& substitution_groups.is_empty()
{
resolved_type = Some(TypeKey::Complex(schema_set.any_type_key()));
}
let resolved_ref = if let Some(ref qname) = ref_name {
let elem_key = resolver.resolve_element_ref(qname, source.as_ref())?;
stats.elements_resolved += 1;
Some(elem_key)
} else {
None
};
let mut resolved_subst_groups = Vec::with_capacity(substitution_groups.len());
for qname in &substitution_groups {
if lazy_src_resolve {
match resolver.try_resolve_element_ref(qname, source.as_ref())? {
Some(elem_key) => {
stats.elements_resolved += 1;
resolved_subst_groups.push(elem_key);
}
None => {
}
}
} else {
let elem_key = resolver.resolve_element_ref(qname, source.as_ref())?;
stats.elements_resolved += 1;
resolved_subst_groups.push(elem_key);
}
}
#[cfg(feature = "xsd11")]
let resolved_alt_types = {
let elem = schema_set
.arenas
.elements
.get(key)
.ok_or_else(|| SchemaError::internal("Element not found in arena"))?;
let mut alt_types: Vec<Option<TypeKey>> = Vec::with_capacity(elem.alternatives.len());
for alt in &elem.alternatives {
if alt.resolved_type.is_some() {
alt_types.push(alt.resolved_type);
} else if let Some(TypeRefResult::QName(ref qname)) = alt.type_ref {
let resolver = ReferenceResolver::new(schema_set);
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
alt_types.push(Some(type_key));
} else {
alt_types.push(resolved_type);
}
}
alt_types
};
if let Some(elem) = schema_set.arenas.elements.get_mut(key) {
elem.resolved_type = resolved_type;
elem.resolved_ref = resolved_ref;
elem.resolved_substitution_groups = resolved_subst_groups;
elem.deferred_type_error = deferred_type_error;
#[cfg(feature = "xsd11")]
for (i, alt_type) in resolved_alt_types.into_iter().enumerate() {
if let Some(alt) = elem.alternatives.get_mut(i) {
alt.resolved_type = alt_type;
}
}
}
Ok(())
}
fn format_type_not_found_message(
schema_set: &SchemaSet,
qname: &QNameRef,
label: &str,
) -> String {
let name_str = format_resolved_qname(&schema_set.name_table, qname.namespace, qname.local_name);
let simple_note = schema_set.format_provenance_note(
ComponentKind::SimpleType,
qname.namespace,
qname.local_name,
);
let note = if simple_note.is_empty() {
schema_set.format_provenance_note(
ComponentKind::ComplexType,
qname.namespace,
qname.local_name,
)
} else {
simple_note
};
format!("{} '{}' not found{}", label, name_str, note)
}
fn build_deferred_type_resolve(
schema_set: &SchemaSet,
qname: &QNameRef,
source: Option<&SourceRef>,
label: &str,
) -> crate::arenas::DeferredSrcResolve {
crate::arenas::DeferredSrcResolve {
message: format_type_not_found_message(schema_set, qname, label),
source: source.cloned(),
}
}
fn resolve_attribute_references(
schema_set: &mut SchemaSet,
key: AttributeKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
let (type_qname, ref_name, source, already_resolved_type) = {
let attr = schema_set
.arenas
.attributes
.get(key)
.ok_or_else(|| SchemaError::internal("Attribute not found in arena"))?;
let type_qname = match &attr.type_ref {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
(
type_qname,
attr.ref_name.clone(),
attr.source.clone(),
attr.resolved_type,
)
};
let resolver = ReferenceResolver::new(schema_set);
let resolved_type = if already_resolved_type.is_some() {
already_resolved_type
} else if let Some(ref qname) = type_qname {
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
} else {
None
};
let resolved_ref = if let Some(ref qname) = ref_name {
let attr_key = resolver.resolve_attribute_ref(qname, source.as_ref())?;
stats.attributes_resolved += 1;
Some(attr_key)
} else {
None
};
if let Some(attr) = schema_set.arenas.attributes.get_mut(key) {
attr.resolved_type = resolved_type;
attr.resolved_ref = resolved_ref;
}
Ok(())
}
fn resolve_simple_type_references(
schema_set: &mut SchemaSet,
key: SimpleTypeKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
let (
base_qname,
item_qname,
member_qnames,
source,
already_resolved_base,
already_resolved_item,
already_resolved_members,
redefine_original,
type_name,
type_ns,
) = {
let type_def = schema_set
.arenas
.simple_types
.get(key)
.ok_or_else(|| SchemaError::internal("Simple type not found in arena"))?;
let base_qname = match &type_def.base_type {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
let item_qname = match &type_def.item_type {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
let member_qnames: Vec<_> = type_def
.member_types
.iter()
.filter_map(|tr| match tr {
TypeRefResult::QName(qname) => Some(qname.clone()),
_ => None,
})
.collect();
(
base_qname,
item_qname,
member_qnames,
type_def.source.clone(),
type_def.resolved_base_type,
type_def.resolved_item_type,
type_def.resolved_member_types.clone(),
type_def.redefine_original,
type_def.name,
type_def.target_namespace,
)
};
let resolver = ReferenceResolver::new(schema_set);
let resolved_base = if already_resolved_base.is_some() {
already_resolved_base
} else if let Some(ref qname) = base_qname {
let is_redefine_self_ref = redefine_original.is_some()
&& Some(qname.local_name) == type_name
&& qname.namespace == type_ns;
if is_redefine_self_ref {
stats.types_resolved += 1;
Some(TypeKey::Simple(redefine_original.unwrap()))
} else {
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
}
} else {
None
};
let lazy_src_resolve = schema_set.is_xsd10();
let mut deferred_item_error: Option<crate::arenas::DeferredSrcResolve> = None;
let resolved_item = if already_resolved_item.is_some() {
already_resolved_item
} else if let Some(ref qname) = item_qname {
if lazy_src_resolve {
match resolver.try_resolve_type_ref(qname, source.as_ref())? {
Some(type_key) => {
stats.types_resolved += 1;
Some(type_key)
}
None => {
deferred_item_error = Some(build_deferred_type_resolve(
schema_set,
qname,
source.as_ref(),
"List item type",
));
None
}
}
} else {
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
}
} else {
None
};
let mut resolved_members = Vec::new();
for qname in &member_qnames {
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
resolved_members.push(type_key);
}
resolved_members.extend(already_resolved_members);
let resolved_base = if resolved_base.is_none() {
let variety = schema_set
.arenas
.simple_types
.get(key)
.map(|t| t.variety)
.unwrap_or(SimpleTypeVariety::Atomic);
if matches!(variety, SimpleTypeVariety::List | SimpleTypeVariety::Union) {
let any_simple = schema_set.builtin_types().any_simple_type;
Some(TypeKey::Simple(any_simple))
} else {
None
}
} else {
resolved_base
};
if let Some(type_def) = schema_set.arenas.simple_types.get_mut(key) {
type_def.resolved_base_type = resolved_base;
type_def.resolved_item_type = resolved_item;
type_def.resolved_member_types = resolved_members;
type_def.deferred_item_type_error = deferred_item_error;
}
if let Some(TypeKey::Simple(base_sk)) = resolved_base {
let (base_variety, base_members, base_item, base_deferred_item) = {
if let Some(base_def) = schema_set.arenas.simple_types.get(base_sk) {
(
base_def.variety,
base_def.resolved_member_types.clone(),
base_def.resolved_item_type,
base_def.deferred_item_type_error.clone(),
)
} else {
(SimpleTypeVariety::Atomic, Vec::new(), None, None)
}
};
if let Some(type_def) = schema_set.arenas.simple_types.get_mut(key) {
if type_def.variety == SimpleTypeVariety::Atomic
&& base_variety != SimpleTypeVariety::Atomic
{
type_def.variety = base_variety;
}
if base_variety == SimpleTypeVariety::Union && type_def.resolved_member_types.is_empty()
{
type_def.resolved_member_types = base_members;
}
if base_variety == SimpleTypeVariety::List && type_def.resolved_item_type.is_none() {
type_def.resolved_item_type = base_item;
if type_def.deferred_item_type_error.is_none() {
type_def.deferred_item_type_error = base_deferred_item;
}
}
}
}
Ok(())
}
fn resolve_complex_type_references(
schema_set: &mut SchemaSet,
key: ComplexTypeKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
use crate::arenas::ResolvedAttributeUse;
let (
base_qname,
attribute_groups,
attribute_uses,
source,
already_resolved_base,
redefine_original,
type_name,
type_ns,
already_resolved_attrs,
) = {
let type_def = schema_set
.arenas
.complex_types
.get(key)
.ok_or_else(|| SchemaError::internal("Complex type not found in arena"))?;
let base_qname = match &type_def.base_type {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
let attribute_uses: Vec<_> = type_def
.attributes
.iter()
.map(|attr_use| {
let type_qname = match &attr_use.attribute.type_ref {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
(
attr_use.attribute.ref_name.clone(),
type_qname,
attr_use.attribute.source.clone(),
)
})
.collect();
let already_resolved_attrs = type_def.resolved_attributes.clone();
(
base_qname,
type_def.attribute_groups.clone(),
attribute_uses,
type_def.source.clone(),
type_def.resolved_base_type,
type_def.redefine_original,
type_def.name,
type_def.target_namespace,
already_resolved_attrs,
)
};
let resolver = ReferenceResolver::new(schema_set);
let resolved_base = if already_resolved_base.is_some() {
already_resolved_base
} else if let Some(ref qname) = base_qname {
let is_redefine_self_ref = redefine_original.is_some()
&& Some(qname.local_name) == type_name
&& qname.namespace == type_ns;
if is_redefine_self_ref {
stats.types_resolved += 1;
Some(TypeKey::Complex(redefine_original.unwrap()))
} else {
let type_key = resolver.resolve_type_ref(qname, source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
}
} else {
None
};
let mut resolved_attr_groups = Vec::with_capacity(attribute_groups.len());
for qname in &attribute_groups {
let group_key = resolver.resolve_attribute_group_ref(qname, source.as_ref())?;
stats.attribute_groups_resolved += 1;
resolved_attr_groups.push(group_key);
}
let mut resolved_attrs = Vec::with_capacity(attribute_uses.len());
for (i, (ref_name, type_qname, attr_source)) in attribute_uses.iter().enumerate() {
let resolved_type = if let Some(ref qname) = type_qname {
let type_key = resolver.resolve_type_ref(qname, attr_source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
} else {
already_resolved_attrs.get(i).and_then(|r| r.resolved_type)
};
let resolved_ref = if let Some(ref qname) = ref_name {
let attr_key = resolver.resolve_attribute_ref(qname, attr_source.as_ref())?;
stats.attributes_resolved += 1;
Some(attr_key)
} else {
already_resolved_attrs.get(i).and_then(|r| r.resolved_ref)
};
resolved_attrs.push(ResolvedAttributeUse {
resolved_type,
resolved_ref,
});
}
if let Some(type_def) = schema_set.arenas.complex_types.get_mut(key) {
type_def.resolved_base_type = resolved_base;
type_def.resolved_attribute_groups = resolved_attr_groups;
type_def.resolved_attributes = resolved_attrs;
}
Ok(())
}
fn resolve_model_group_references(
schema_set: &mut SchemaSet,
key: ModelGroupKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
use crate::arenas::ResolvedParticleTerm;
use crate::parser::frames::ParticleTerm;
let group = schema_set
.arenas
.model_groups
.get(key)
.ok_or_else(|| SchemaError::internal("Model group not found in arena"))?;
let ref_name = group.ref_name.clone();
let source = group.source.clone();
let particles_clone = group.particles.clone();
let redefine_original = group.redefine_original;
let group_name = group.name;
let group_ns = group.target_namespace;
let existing_resolved: Vec<_> = group.resolved_particles.clone();
let existing_particle_types = group.resolved_particle_types.clone();
let particle_info: Vec<_> = group
.particles
.iter()
.map(|p| match &p.term {
ParticleTerm::Element(elem) => {
let type_qname = match &elem.type_ref {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
(0, elem.ref_name.clone(), type_qname, p.source.clone())
}
ParticleTerm::Group(grp) => (1, grp.ref_name.clone(), None, p.source.clone()),
ParticleTerm::Any(_) => (2, None, None, p.source.clone()),
})
.collect();
let resolver = ReferenceResolver::new(schema_set);
let resolved_ref = if let Some(ref qname) = ref_name {
let group_key = resolver.resolve_group_ref(qname, source.as_ref())?;
stats.groups_resolved += 1;
Some(group_key)
} else {
None
};
let mut resolved_particles = Vec::with_capacity(particle_info.len());
for (i, (kind, elem_or_group_ref, type_qname, particle_source)) in
particle_info.iter().enumerate()
{
match kind {
0 => {
let already_resolved_type = existing_resolved.get(i).and_then(|rp| {
if let ResolvedParticleTerm::Element {
resolved_type: Some(key),
..
} = rp
{
Some(*key)
} else {
None
}
});
let resolved_type = if let Some(key) = already_resolved_type {
Some(key)
} else if let Some(ref qname) = type_qname {
let type_key = resolver.resolve_type_ref(qname, particle_source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
} else {
None
};
let resolved_elem_ref = if let Some(ref qname) = elem_or_group_ref {
let elem_key = resolver.resolve_element_ref(qname, particle_source.as_ref())?;
stats.elements_resolved += 1;
Some(elem_key)
} else {
None
};
resolved_particles.push(ResolvedParticleTerm::Element {
resolved_type,
resolved_ref: resolved_elem_ref,
});
}
1 => {
let resolved_group_ref = if let Some(ref qname) = elem_or_group_ref {
let is_self_ref = redefine_original.is_some()
&& Some(qname.local_name) == group_name
&& qname.namespace == group_ns;
let grp_key = if is_self_ref {
redefine_original.unwrap()
} else {
resolver.resolve_group_ref(qname, particle_source.as_ref())?
};
stats.groups_resolved += 1;
Some(grp_key)
} else {
None
};
resolved_particles.push(ResolvedParticleTerm::Group {
resolved_ref: resolved_group_ref,
});
}
_ => {
resolved_particles.push(ResolvedParticleTerm::Any);
}
}
}
let mut resolved_particle_types = Vec::new();
let mut flat_idx = 0;
resolve_model_group_particle_types_recursive(
&particles_clone,
&existing_particle_types,
&resolver,
&mut flat_idx,
&mut resolved_particle_types,
stats,
)?;
if let Some(group) = schema_set.arenas.model_groups.get_mut(key) {
group.resolved_ref = resolved_ref;
group.resolved_particles = resolved_particles;
group.resolved_particle_types = resolved_particle_types;
}
Ok(())
}
fn resolve_model_group_particle_types_recursive(
particles: &[crate::parser::frames::ParticleResult],
existing_types: &[Option<TypeKey>],
resolver: &ReferenceResolver,
flat_idx: &mut usize,
resolved_types: &mut Vec<Option<TypeKey>>,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
use crate::parser::frames::ParticleTerm;
for particle in particles {
match &particle.term {
ParticleTerm::Element(elem) => {
let idx = *flat_idx;
*flat_idx += 1;
let already_resolved = existing_types.get(idx).copied().flatten();
let resolved_type = if let Some(key) = already_resolved {
Some(key)
} else {
match &elem.type_ref {
Some(TypeRefResult::QName(qname)) => {
let type_key =
resolver.resolve_type_ref(qname, particle.source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
}
_ => None,
}
};
while resolved_types.len() <= idx {
resolved_types.push(None);
}
resolved_types[idx] = resolved_type;
}
ParticleTerm::Group(group_def) if group_def.ref_name.is_none() => {
resolve_model_group_particle_types_recursive(
&group_def.particles,
existing_types,
resolver,
flat_idx,
resolved_types,
stats,
)?;
}
_ => {} }
}
Ok(())
}
fn resolve_attribute_group_references(
schema_set: &mut SchemaSet,
key: AttributeGroupKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
use crate::arenas::ResolvedAttributeUse;
let group = schema_set
.arenas
.attribute_groups
.get(key)
.ok_or_else(|| SchemaError::internal("Attribute group not found in arena"))?;
let ref_name = group.ref_name.clone();
let nested_groups = group.attribute_groups.clone();
let source = group.source.clone();
let redefine_original = group.redefine_original;
let group_name = group.name;
let group_ns = group.target_namespace;
let attribute_uses: Vec<_> = group
.attributes
.iter()
.map(|attr_use| {
let type_qname = match &attr_use.attribute.type_ref {
Some(TypeRefResult::QName(qname)) => Some(qname.clone()),
_ => None,
};
(
attr_use.attribute.ref_name.clone(),
type_qname,
attr_use.attribute.source.clone(),
)
})
.collect();
let already_resolved_attrs = group.resolved_attributes.clone();
let resolver = ReferenceResolver::new(schema_set);
let resolved_ref = if let Some(ref qname) = ref_name {
let group_key = resolver.resolve_attribute_group_ref(qname, source.as_ref())?;
stats.attribute_groups_resolved += 1;
Some(group_key)
} else {
None
};
let mut resolved_nested = Vec::with_capacity(nested_groups.len());
for qname in &nested_groups {
let is_self_ref = redefine_original.is_some()
&& Some(qname.local_name) == group_name
&& qname.namespace == group_ns;
let group_key = if is_self_ref {
redefine_original.unwrap()
} else {
resolver.resolve_attribute_group_ref(qname, source.as_ref())?
};
stats.attribute_groups_resolved += 1;
resolved_nested.push(group_key);
}
let mut resolved_attrs = Vec::with_capacity(attribute_uses.len());
for (i, (ref_name_opt, type_qname, attr_source)) in attribute_uses.iter().enumerate() {
let resolved_type = if let Some(ref qname) = type_qname {
let type_key = resolver.resolve_type_ref(qname, attr_source.as_ref())?;
stats.types_resolved += 1;
Some(type_key)
} else {
already_resolved_attrs.get(i).and_then(|r| r.resolved_type)
};
let resolved_attr_ref = if let Some(ref qname) = ref_name_opt {
let attr_key = resolver.resolve_attribute_ref(qname, attr_source.as_ref())?;
stats.attributes_resolved += 1;
Some(attr_key)
} else {
already_resolved_attrs.get(i).and_then(|r| r.resolved_ref)
};
resolved_attrs.push(ResolvedAttributeUse {
resolved_type,
resolved_ref: resolved_attr_ref,
});
}
if let Some(group) = schema_set.arenas.attribute_groups.get_mut(key) {
group.resolved_ref = resolved_ref;
group.resolved_attribute_groups = resolved_nested;
group.resolved_attributes = resolved_attrs;
}
Ok(())
}
fn resolve_notation_references(
schema_set: &mut SchemaSet,
key: NotationKey,
stats: &mut ResolutionStats,
) -> SchemaResult<()> {
let _notation = schema_set
.arenas
.notations
.get(key)
.ok_or_else(|| SchemaError::internal("Notation not found in arena"))?;
stats.notations_resolved += 1;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::namespace::table::well_known;
#[test]
fn test_reference_resolver_creation() {
let schema_set = SchemaSet::new();
let _resolver = ReferenceResolver::new(&schema_set);
}
#[test]
fn test_resolve_builtin_type() {
let schema_set = SchemaSet::new();
let resolver = ReferenceResolver::new(&schema_set);
let string_name = schema_set.name_table.get("string").unwrap();
let qname = QNameRef {
prefix: None,
local_name: string_name,
namespace: Some(well_known::XS_NAMESPACE),
};
let result = resolver.resolve_type_ref(&qname, None);
assert!(result.is_ok(), "Should resolve xs:string");
if let Ok(TypeKey::Simple(key)) = result {
let string_key = schema_set.builtin_types().string;
assert_eq!(key, string_key);
} else {
panic!("Expected Simple type key");
}
}
#[test]
fn test_resolve_builtin_integer() {
let schema_set = SchemaSet::new();
let resolver = ReferenceResolver::new(&schema_set);
let integer_name = schema_set.name_table.get("integer").unwrap();
let qname = QNameRef {
prefix: None,
local_name: integer_name,
namespace: Some(well_known::XS_NAMESPACE),
};
let result = resolver.resolve_type_ref(&qname, None);
assert!(result.is_ok(), "Should resolve xs:integer");
}
#[test]
fn test_resolve_builtin_any_type() {
let schema_set = SchemaSet::new();
let resolver = ReferenceResolver::new(&schema_set);
let any_type_name = schema_set.name_table.get("anyType").unwrap();
let qname = QNameRef {
prefix: None,
local_name: any_type_name,
namespace: Some(well_known::XS_NAMESPACE),
};
let result = resolver.resolve_type_ref(&qname, None);
assert!(result.is_ok(), "Should resolve xs:anyType");
if let Ok(TypeKey::Complex(key)) = result {
assert_eq!(key, schema_set.builtin_types().any_type);
} else {
panic!("Expected Complex type key");
}
}
#[test]
fn test_resolve_unknown_type_error() {
let schema_set = SchemaSet::new();
let unknown_name = schema_set.name_table.add("nonExistentType");
let resolver = ReferenceResolver::new(&schema_set);
let qname = QNameRef {
prefix: None,
local_name: unknown_name,
namespace: Some(well_known::XS_NAMESPACE),
};
let result = resolver.resolve_type_ref(&qname, None);
assert!(result.is_err(), "Should fail for unknown type");
}
#[test]
fn test_format_qname_with_namespace() {
let schema_set = SchemaSet::new();
let resolver = ReferenceResolver::new(&schema_set);
let string_name = schema_set.name_table.get("string").unwrap();
let qname = QNameRef {
prefix: None,
local_name: string_name,
namespace: Some(well_known::XS_NAMESPACE),
};
let formatted = resolver.format_qname(&qname);
assert!(formatted.contains("string"));
assert!(formatted.contains("XMLSchema"));
}
#[test]
fn test_format_qname_without_namespace() {
let schema_set = SchemaSet::new();
let local_name = schema_set.name_table.add("localType");
let resolver = ReferenceResolver::new(&schema_set);
let qname = QNameRef {
prefix: None,
local_name,
namespace: None,
};
let formatted = resolver.format_qname(&qname);
assert_eq!(formatted, "localType");
}
#[test]
fn test_resolution_stats_default() {
let stats = ResolutionStats::default();
assert_eq!(stats.types_resolved, 0);
assert_eq!(stats.elements_resolved, 0);
assert_eq!(stats.errors, 0);
}
#[test]
fn test_resolve_all_references_empty_schema() {
let mut schema_set = SchemaSet::new();
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok());
let stats = result.unwrap();
assert_eq!(stats.errors, 0);
}
#[test]
fn test_resolve_user_defined_element_with_builtin_type() {
use crate::arenas::ElementDeclData;
use crate::parser::frames::QNameRef;
use crate::schema::model::DerivationSet;
let mut schema_set = SchemaSet::new();
let elem_name = schema_set.name_table.add("myElement");
let string_name = schema_set.name_table.get("string").unwrap();
let type_ref = TypeRefResult::QName(QNameRef {
prefix: None,
local_name: string_name,
namespace: Some(well_known::XS_NAMESPACE),
});
let elem_data = ElementDeclData {
name: Some(elem_name),
target_namespace: None,
ref_name: None,
type_ref: Some(type_ref),
inline_type: None,
substitution_group: Vec::new(),
default_value: None,
fixed_value: None,
nillable: false,
is_abstract: false,
min_occurs: 1,
max_occurs: Some(1),
block: DerivationSet::empty(),
final_derivation: DerivationSet::empty(),
form: None,
id: None,
alternatives: Vec::new(),
identity_constraints: Vec::new(),
pending_ic_refs: vec![],
annotation: None,
source: None,
resolved_type: None,
resolved_ref: None,
resolved_substitution_groups: Vec::new(),
deferred_type_error: None,
};
let elem_key = schema_set.arenas.alloc_element(elem_data);
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok(), "Resolution should succeed: {:?}", result);
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(elem.resolved_type.is_some(), "Type should be resolved");
if let Some(TypeKey::Simple(key)) = elem.resolved_type {
assert_eq!(key, schema_set.builtin_types().string);
} else {
panic!("Expected Simple type key for xs:string");
}
}
#[test]
fn test_resolve_attribute_with_builtin_type() {
use crate::arenas::AttributeDeclData;
use crate::parser::frames::QNameRef;
let mut schema_set = SchemaSet::new();
let attr_name = schema_set.name_table.add("myAttribute");
let integer_name = schema_set.name_table.get("integer").unwrap();
let type_ref = TypeRefResult::QName(QNameRef {
prefix: None,
local_name: integer_name,
namespace: Some(well_known::XS_NAMESPACE),
});
let attr_data = AttributeDeclData {
name: Some(attr_name),
target_namespace: None,
ref_name: None,
type_ref: Some(type_ref),
inline_type: None,
default_value: None,
fixed_value: None,
use_kind: None,
form: None,
inheritable: false,
id: None,
annotation: None,
source: None,
resolved_type: None,
resolved_ref: None,
};
let attr_key = schema_set.arenas.alloc_attribute(attr_data);
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok());
let attr = schema_set.arenas.attributes.get(attr_key).unwrap();
assert!(attr.resolved_type.is_some(), "Type should be resolved");
}
#[test]
fn test_resolve_element_already_resolved_inline_type() {
use crate::arenas::ElementDeclData;
use crate::schema::model::DerivationSet;
let mut schema_set = SchemaSet::new();
let elem_name = schema_set.name_table.add("myElement");
let string_key = schema_set.builtin_types().string;
let elem_data = ElementDeclData {
name: Some(elem_name),
target_namespace: None,
ref_name: None,
type_ref: None,
inline_type: None,
substitution_group: Vec::new(),
default_value: None,
fixed_value: None,
nillable: false,
is_abstract: false,
min_occurs: 1,
max_occurs: Some(1),
block: DerivationSet::empty(),
final_derivation: DerivationSet::empty(),
form: None,
id: None,
alternatives: Vec::new(),
identity_constraints: Vec::new(),
pending_ic_refs: vec![],
annotation: None,
source: None,
resolved_type: Some(TypeKey::Simple(string_key)),
resolved_ref: None,
resolved_substitution_groups: Vec::new(),
deferred_type_error: None,
};
let elem_key = schema_set.arenas.alloc_element(elem_data);
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok());
let elem = schema_set.arenas.elements.get(elem_key).unwrap();
assert!(elem.resolved_type.is_some());
assert_eq!(elem.resolved_type, Some(TypeKey::Simple(string_key)));
}
#[test]
fn test_resolver_preserves_inline_resolved_type_in_model_group() {
use crate::arenas::{ModelGroupData, ResolvedParticleTerm};
use crate::parser::frames::{Compositor, ElementFrameResult, ParticleResult, ParticleTerm};
let mut schema_set = SchemaSet::new();
let elem_name = schema_set.name_table.add("detail");
let group_name = schema_set.name_table.add("myGroup");
let string_key = schema_set.builtin_types().string;
let group_data = ModelGroupData {
name: Some(group_name),
target_namespace: None,
ref_name: None,
compositor: Some(Compositor::Sequence),
particles: vec![ParticleResult {
term: ParticleTerm::Element(ElementFrameResult {
name: Some(elem_name),
ref_name: None,
target_namespace: None,
type_ref: None, inline_type: None,
substitution_group: vec![],
default_value: None,
fixed_value: None,
nillable: false,
is_abstract: false,
min_occurs: 1,
max_occurs: Some(1),
block: None,
final_derivation: None,
form: None,
id: None,
alternatives: vec![],
identity_constraints: vec![],
identity_constraint_refs: vec![],
annotation: None,
source: None,
}),
min_occurs: 1,
max_occurs: Some(1),
source: None,
}],
min_occurs: 1,
max_occurs: Some(1),
id: None,
annotation: None,
source: None,
resolved_ref: None,
resolved_particles: vec![ResolvedParticleTerm::Element {
resolved_type: Some(TypeKey::Simple(string_key)),
resolved_ref: None,
}],
resolved_particle_types: vec![Some(TypeKey::Simple(string_key))],
resolved_particle_elements: Vec::new(),
redefine_original: None,
redefine_requires_restriction_check: false,
};
let group_key = schema_set.arenas.alloc_model_group(group_data);
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok());
let group = schema_set.arenas.model_groups.get(group_key).unwrap();
assert_eq!(group.resolved_particles.len(), 1);
match &group.resolved_particles[0] {
ResolvedParticleTerm::Element {
resolved_type: Some(TypeKey::Simple(key)),
..
} => {
assert_eq!(*key, string_key, "Inline-resolved type should be preserved");
}
other => panic!("Expected Element with pre-resolved type, got {:?}", other),
}
}
fn setup_default_attrs_test(
default_attributes_apply: bool,
) -> (
SchemaSet,
crate::ids::ComplexTypeKey,
crate::ids::AttributeGroupKey,
) {
use crate::arenas::{AttributeGroupData, ComplexTypeDefData};
use crate::namespace::QualifiedName;
use crate::parser::frames::ComplexContentResult;
use crate::parser::location::{SourceRef, SourceSpan};
use crate::schema::model::{DerivationSet, SchemaDocument};
let mut schema_set = SchemaSet::new();
let group_name = schema_set.name_table.add("commonAttrs");
let group_data = AttributeGroupData {
name: Some(group_name),
target_namespace: None,
ref_name: None,
attributes: Vec::new(),
attribute_groups: Vec::new(),
attribute_wildcard: None,
id: None,
annotation: None,
source: None,
resolved_ref: None,
resolved_attribute_groups: Vec::new(),
resolved_attributes: Vec::new(),
redefine_original: None,
redefine_requires_restriction_check: false,
};
let group_key = schema_set.arenas.alloc_attribute_group(group_data);
schema_set
.get_or_create_namespace(None)
.register_attribute_group(group_name, group_key);
let doc_id = schema_set.documents.len() as u32;
let mut doc = SchemaDocument::new(doc_id, "test.xsd".to_string());
doc.default_attributes = Some(QualifiedName::local(group_name));
schema_set.documents.push(doc);
let type_name = schema_set.name_table.add("myType");
let ct_data = ComplexTypeDefData {
name: Some(type_name),
target_namespace: None,
base_type: None,
derivation_method: None,
content: ComplexContentResult::Empty,
open_content: None,
attributes: Vec::new(),
attribute_groups: Vec::new(),
attribute_wildcard: None,
mixed: false,
is_abstract: false,
final_derivation: DerivationSet::empty(),
block: DerivationSet::empty(),
default_attributes_apply,
id: None,
#[cfg(feature = "xsd11")]
assertions: Vec::new(),
#[cfg(feature = "xsd11")]
xpath_default_namespace: None,
annotation: None,
source: Some(SourceRef::new(doc_id, SourceSpan::new(0, 0))),
resolved_base_type: None,
resolved_attribute_groups: Vec::new(),
resolved_attributes: Vec::new(),
resolved_content_particle_types: Vec::new(),
resolved_content_particle_elements: Vec::new(),
resolved_simple_content_type: None,
redefine_original: None,
};
let ct_key = schema_set.arenas.alloc_complex_type(ct_data);
(schema_set, ct_key, group_key)
}
#[test]
fn test_resolve_default_attributes_injects_group() {
let (mut schema_set, ct_key, group_key) = setup_default_attrs_test(true);
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok(), "Resolution should succeed: {:?}", result);
let ct = schema_set.arenas.complex_types.get(ct_key).unwrap();
assert!(
ct.resolved_attribute_groups.contains(&group_key),
"Default attribute group should be injected into resolved_attribute_groups"
);
}
#[test]
fn test_resolve_default_attributes_opt_out() {
let (mut schema_set, ct_key, _group_key) = setup_default_attrs_test(false);
let result = resolve_all_references(&mut schema_set);
assert!(result.is_ok(), "Resolution should succeed: {:?}", result);
let ct = schema_set.arenas.complex_types.get(ct_key).unwrap();
assert!(
ct.resolved_attribute_groups.is_empty(),
"Default attribute group should NOT be injected when defaultAttributesApply=false"
);
}
}