package XML::Validator::Schema::RootNode; use strict; use warnings; use base 'XML::Validator::Schema::ElementNode'; use XML::Validator::Schema::Util qw(_err); use Carp qw(croak); =head1 NAME XML::Validator::Schema::RootNode - the root node in a schema document =head1 DESCRIPTION This is an internal module used by XML::Validator::Schema to represent the root node in an XML Schema document. Holds references to the libraries for the schema document and is responsible for hooking up named types to their uses in the node tree at the end of parsing. =cut sub new { my $pkg = shift; my $self = $pkg->SUPER::new(@_); # start up with empty libraries $self->{type_library} = XML::Validator::Schema::TypeLibrary->new; $self->{element_library} = XML::Validator::Schema::ElementLibrary->new; $self->{attribute_library} = XML::Validator::Schema::AttributeLibrary->new; return $self; } # finish typing and references sub compile { my $self = shift; my $element_library = $self->{element_library}; # put global elements into the library (could move this to ::ElementNode) foreach my $d ($self->daughters) { if (ref($d) eq 'XML::Validator::Schema::ElementNode') { $element_library->add(name => $d->{name}, obj => $d); } } # complete all element refs first, forming a complete tree foreach my $element ($self->descendants) { $self->complete_ref($element); } # completa all element types, including their attributes foreach my $element ($self->descendants) { $self->complete_type($element); } } sub complete_ref { my ($self, $ref) = @_; # handle any unresolved attribute types if ($ref->{attr}) { $self->complete_attr_ref($_) for (grep { $_->{unresolved_ref} } (@{$ref->{attr}})); } # all done unless unresolved return unless $ref->{unresolved_ref}; my $name = $ref->{name}; my ($element) = $self->{element_library}->find(name => $ref->{name}); _err("Found unresolved reference to element '$name'") unless $element; # replace the current element $ref->replace_with($element->copy_at_and_under); return; } sub complete_type { my ($self, $element) = @_; my $library = $self->{type_library}; # handle any unresolved attribute types if ($element->{attr}) { $self->complete_attr_type($_) for (grep { $_->{unresolved_type} } (@{$element->{attr}})); } # all done unless unresolved return unless $element->{unresolved_type}; # get type data my $type_name = $element->{type_name}; my $type = $library->find(name => $type_name); # isn't there? _err("Element '<$element->{name}>' has unrecognized type '$type_name'.") unless $type; if ($type->isa('XML::Validator::Schema::ComplexTypeNode')) { # can't have daughters for this to work _err("Element '<$element->{name}>' is using a named complexType and has sub-elements of its own. That's not supported.") if $element->daughters; # replace the current element with one based on the complex node my $new_node = $type->copy_at_and_under; $new_node->name($element->{name}); $new_node->{attr} = [ @{ $new_node->{attr} || [] }, @{ $element->{attr} || [] } ]; $element->replace_with($new_node); } elsif ($type->isa('XML::Validator::Schema::SimpleType')) { $element->{type} = $type; } else { croak("Library returned '$type'!"); } # fixed it delete $element->{unresolved_type}; } sub complete_attr_type { my ($self, $attr) = @_; my $type = $self->{type_library}->find(name => $attr->{type_name}); _err("Attribute '<$attr->{name}>' has unrecognized ". "type '$attr->{type_name}'.") unless $type; $attr->{type} = $type; delete $attr->{unresolved_type}; } sub complete_attr_ref { my ($self, $ref) = @_; my $attr = $self->{attribute_library}->find(name => $ref->{name}); _err("Attribute reference '$ref->{name}' not found.") unless $attr; # clone, keep use my $use = $ref->{required}; %$ref = %$attr; $ref->{required} = $use; return; } 1;