18
+ − 1 package IMPL::DOM::Navigator::SchemaNavigator;
+ − 2 use strict;
+ − 3 use warnings;
+ − 4
+ − 5 use base qw(IMPL::DOM::Navigator);
+ − 6 use IMPL::Class::Property;
+ − 7 use IMPL::Class::Property::Direct;
+ − 8
24
+ − 9 require IMPL::DOM::Schema::ComplexType;
+ − 10 require IMPL::DOM::Schema::NodeSet;
+ − 11 require IMPL::DOM::Schema::AnyNode;
+ − 12
18
+ − 13 __PACKAGE__->PassThroughArgs;
+ − 14
+ − 15 BEGIN {
+ − 16 public _direct property Schema => prop_get;
24
+ − 17 private _direct property _historySteps => prop_all;
18
+ − 18 }
+ − 19
+ − 20 sub CTOR {
+ − 21 my ($this,$schema) = @_;
+ − 22
+ − 23 $this->{$Schema} = $schema;
+ − 24
+ − 25 die new IMPL::InvalidArgumentException("A schema object is required") unless $schema->isa('IMPL::DOM::Schema');
+ − 26 }
+ − 27
24
+ − 28 my $schemaAnyNode = IMPL::DOM::Schema::ComplexType->new(type => '::AnyNodeType', nativeType => 'IMPL::DOM::ComplexNode')->appendRange(
+ − 29 IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ − 30 IMPL::DOM::Schema::AnyNode->new()
+ − 31 )
+ − 32 );
+ − 33
+ − 34 sub NavigateName {
+ − 35 my ($this,$name) = @_;
18
+ − 36
24
+ − 37 # perform a safe navigation
+ − 38 return dosafe $this sub {
+ − 39 my $steps = 1;
+ − 40 # navigate to node
+ − 41 if (
+ − 42 my $node = $this->Navigate( sub {
+ − 43 $_->isa('IMPL::DOM::Schema::Node') and (
+ − 44 $_->name eq $name
+ − 45 or
+ − 46 $_->nodeName eq 'AnyNode'
+ − 47 or
+ − 48 ( $_->nodeName eq 'SwitchNode' and $_->selectNodes( sub { $_->name eq $name } ) )
+ − 49 )
+ − 50 })
+ − 51 ) {
+ − 52 if ($node->nodeName eq 'AnyNode') {
+ − 53 # if we navigate to the anynode
+ − 54 # assume it to be ComplexType by default
+ − 55 $node = $node->type ? $this->{$Schema}->resolveType($node->type) : $schemaAnyNode;
+ − 56 } elsif ($node->nodeName eq 'SwitchNode') {
+ − 57 # if we are in the switchnode
+ − 58 # navigate to the target node
+ − 59 $node = $this->Navigate(sub { $_->name eq $name });
+ − 60 $steps ++;
+ − 61 }
+ − 62
+ − 63 if ($node->nodeName eq 'Node') {
+ − 64 # if we navigate to a reference
+ − 65 # resolve it
+ − 66 $node = $this->{$Schema}->resolveType($node->type);
+ − 67 $this->internalNavigateNodeSet($node);
+ − 68 $steps++;
+ − 69 }
+ − 70
+ − 71 # if target node is a complex node
+ − 72 if ($node->isa('IMPL::DOM::Schema::ComplexNode')) {
+ − 73 # navigate to it's content
+ − 74 $this->internalNavigateNodeSet($node->content);
+ − 75 $steps ++;
+ − 76 }
+ − 77
+ − 78 push @{$this->{$_historySteps}},$steps;
+ − 79
+ − 80 # return found node schema
+ − 81 return $node;
+ − 82 } else {
+ − 83 die; # abort navigation
18
+ − 84 }
+ − 85 }
+ − 86 }
+ − 87
24
+ − 88 sub SchemaBack {
+ − 89 my ($this) = @_;
+ − 90
+ − 91 $this->Back(pop @{$this->{$_historySteps}}) if $this->{$_historySteps};
+ − 92 }
+ − 93
18
+ − 94 1;
+ − 95 __END__
+ − 96
+ − 97 =pod
+ − 98
+ − 99 =head1 DESCRIPTION
+ − 100
24
+ − 101 ������ ����������� ������� ��������� ��������� ���������� �� ��������� ���������,
+ − 102 ������� ������ ������ �����������.
+ − 103
+ − 104 =head1 METHODS
+ − 105
+ − 106 =over
+ − 107
+ − 108 =item C<< $navi->NavigateName($name) >>
+ − 109
+ − 110 ��������� �� ����� ���� � ��������� ������. ������ ���������� �������� C<name>
+ − 111
+ − 112 =item C<< $navi->SchemaBack >>
+ − 113
+ − 114 ������������ �� ������� �� ��������� �������� C<NavigateName>. ������ ����� �����
+ − 115 ���������� �������� ��������� �� ��������� ����������� ������ ����� ��������� �
+ − 116 ���������� ��������� ��������� �� ����� �����.
+ − 117
+ − 118 =back
18
+ − 119
+ − 120 =cut