File Coverage

blib/lib/XML/Validator/Schema/RootNode.pm
Criterion Covered Total %
statement 15 74 20.2
branch 0 28 0.0
condition n/a
subroutine 5 11 45.4
pod 1 6 16.6
total 21 119 17.6


line stmt bran cond sub pod time code
1             package XML::Validator::Schema::RootNode;
2 5     5   29 use strict;
  5         7  
  5         153  
3 5     5   60 use warnings;
  5         10  
  5         142  
4              
5 5     5   36 use base 'XML::Validator::Schema::ElementNode';
  5         8  
  5         379  
6              
7 5     5   31 use XML::Validator::Schema::Util qw(_err);
  5         9  
  5         247  
8 5     5   24 use Carp qw(croak);
  5         8  
  5         4634  
9              
10             =head1 NAME
11              
12             XML::Validator::Schema::RootNode - the root node in a schema document
13              
14             =head1 DESCRIPTION
15              
16             This is an internal module used by XML::Validator::Schema to represent
17             the root node in an XML Schema document. Holds references to the
18             libraries for the schema document and is responsible for hooking up
19             named types to their uses in the node tree at the end of parsing.
20              
21             =cut
22              
23             sub new {
24 0     0 1   my $pkg = shift;
25 0           my $self = $pkg->SUPER::new(@_);
26              
27             # start up with empty libraries
28 0           $self->{type_library} = XML::Validator::Schema::TypeLibrary->new;
29 0           $self->{element_library} = XML::Validator::Schema::ElementLibrary->new;
30 0           $self->{attribute_library} = XML::Validator::Schema::AttributeLibrary->new;
31              
32 0           return $self;
33             }
34              
35             # finish typing and references
36             sub compile {
37 0     0 0   my $self = shift;
38 0           my $element_library = $self->{element_library};
39              
40             # put global elements into the library (could move this to ::ElementNode)
41 0           foreach my $d ($self->daughters) {
42 0 0         if (ref($d) eq 'XML::Validator::Schema::ElementNode') {
43 0           $element_library->add(name => $d->{name},
44             obj => $d);
45             }
46             }
47              
48              
49             # complete all element refs first, forming a complete tree
50 0           foreach my $element ($self->descendants) {
51 0           $self->complete_ref($element);
52             }
53              
54             # completa all element types, including their attributes
55 0           foreach my $element ($self->descendants) {
56 0           $self->complete_type($element);
57             }
58              
59             }
60              
61             sub complete_ref {
62 0     0 0   my ($self, $ref) = @_;
63              
64             # handle any unresolved attribute types
65 0 0         if ($ref->{attr}) {
66 0           $self->complete_attr_ref($_)
67 0           for (grep { $_->{unresolved_ref} } (@{$ref->{attr}}));
  0            
68             }
69              
70             # all done unless unresolved
71 0 0         return unless $ref->{unresolved_ref};
72              
73 0           my $name = $ref->{name};
74 0           my ($element) = $self->{element_library}->find(name => $ref->{name});
75 0 0         _err("Found unresolved reference to element '$name'")
76             unless $element;
77              
78              
79              
80             # replace the current element
81 0           $ref->replace_with($element->copy_at_and_under);
82              
83 0           return;
84             }
85              
86             sub complete_type {
87 0     0 0   my ($self, $element) = @_;
88 0           my $library = $self->{type_library};
89              
90             # handle any unresolved attribute types
91 0 0         if ($element->{attr}) {
92 0           $self->complete_attr_type($_)
93 0           for (grep { $_->{unresolved_type} } (@{$element->{attr}}));
  0            
94             }
95              
96             # all done unless unresolved
97 0 0         return unless $element->{unresolved_type};
98              
99             # get type data
100 0           my $type_name = $element->{type_name};
101 0           my $type = $library->find(name => $type_name);
102              
103             # isn't there?
104 0 0         _err("Element '<$element->{name}>' has unrecognized type '$type_name'.")
105             unless $type;
106              
107              
108 0 0         if ($type->isa('XML::Validator::Schema::ComplexTypeNode')) {
    0          
109             # can't have daughters for this to work
110 0 0         _err("Element '<$element->{name}>' is using a named complexType and has sub-elements of its own. That's not supported.")
111             if $element->daughters;
112            
113             # replace the current element with one based on the complex node
114 0           my $new_node = $type->copy_at_and_under;
115 0           $new_node->name($element->{name});
116 0 0         $new_node->{attr} = [ @{ $new_node->{attr} || [] },
  0 0          
117 0           @{ $element->{attr} || [] } ];
118 0           $element->replace_with($new_node);
119              
120              
121             } elsif ($type->isa('XML::Validator::Schema::SimpleType')) {
122 0           $element->{type} = $type;
123              
124             } else {
125 0           croak("Library returned '$type'!");
126             }
127              
128             # fixed it
129 0           delete $element->{unresolved_type};
130             }
131              
132             sub complete_attr_type {
133 0     0 0   my ($self, $attr) = @_;
134              
135 0           my $type = $self->{type_library}->find(name => $attr->{type_name});
136 0 0         _err("Attribute '<$attr->{name}>' has unrecognized ".
137             "type '$attr->{type_name}'.")
138             unless $type;
139              
140 0           $attr->{type} = $type;
141 0           delete $attr->{unresolved_type};
142             }
143              
144             sub complete_attr_ref {
145 0     0 0   my ($self, $ref) = @_;
146              
147 0           my $attr = $self->{attribute_library}->find(name => $ref->{name});
148 0 0         _err("Attribute reference '$ref->{name}' not found.")
149             unless $attr;
150            
151             # clone, keep use
152 0           my $use = $ref->{required};
153 0           %$ref = %$attr;
154 0           $ref->{required} = $use;
155              
156 0           return;
157             }
158              
159              
160              
161             1;