annotate lib/IMPL/DOM/Navigator/SchemaNavigator.pm @ 408:5c80e33f1218 ref20150831

added 'coarsen' function
author cin
date Mon, 07 Sep 2015 01:35:25 +0300
parents c6e90e02dd17
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
407
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
1 package IMPL::DOM::Navigator::SchemaNavigator;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
2 use strict;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
3 use warnings;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
4
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
5 use IMPL::Class::Property;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
6
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
7 require IMPL::DOM::Schema::ComplexType;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
8 require IMPL::DOM::Schema::NodeSet;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
9 require IMPL::DOM::Schema::AnyNode;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
10
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
11 use IMPL::declare {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
12 base => [
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
13 'IMPL::DOM::Navigator' => '@_'
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
14 ]
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
15 };
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
16
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
17 BEGIN {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
18 public _direct property Schema => prop_get;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
19 private _direct property _historySteps => prop_all;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
20 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
21
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
22 sub CTOR {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
23 my ($this,$schema) = @_;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
24
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
25 $this->{$Schema} = $schema->isa('IMPL::DOM::Schema::ComplexNode') ? $schema->document : $schema;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
26
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
27 die new IMPL::InvalidArgumentException("A schema object is required") unless ref $this->{$Schema} && eval { $this->{$Schema}->isa('IMPL::DOM::Schema') };
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
28 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
29
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
30 my $schemaAnyNode = IMPL::DOM::Schema::ComplexType->new(type => '::AnyNodeType', nativeType => 'IMPL::DOM::ComplexNode')->appendRange(
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
31 IMPL::DOM::Schema::NodeSet->new()->appendRange(
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
32 IMPL::DOM::Schema::AnyNode->new()
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
33 )
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
34 );
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
35
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
36 sub NavigateName {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
37 my ($this,$name) = @_;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
38
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
39 die new IMPL::InvalidArgumentException('name is required') unless defined $name;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
40
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
41 # perform a safe navigation
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
42 #return dosafe $this sub {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
43 my $steps = 0;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
44 # if we are currently in a ComplexNode, first go to it's content
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
45 if ($this->Current->isa('IMPL::DOM::Schema::ComplexNode')) {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
46 # navigate to it's content
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
47 # ComplexNode
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
48 $this->internalNavigateNodeSet($this->Current->content);
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
49 $steps ++;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
50 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
51
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
52 # navigate to node
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
53 if (
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
54 my $node = $this->Navigate( sub {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
55 $_->isa('IMPL::DOM::Schema::Node') and (
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
56 $_->name eq $name
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
57 or
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
58 $_->nodeName eq 'AnyNode'
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
59 or
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
60 ( $_->nodeName eq 'SwitchNode' and $_->selectNodes( sub { $_->name eq $name } ) )
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
61 )
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
62 })
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
63 ) {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
64 $steps ++;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
65 if ($node->nodeName eq 'AnyNode') {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
66 # if we navigate to the anynode
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
67 # assume it to be ComplexType by default
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
68 $node = $node->type ? $this->{$Schema}->resolveType($node->type) : $schemaAnyNode;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
69 $this->internalNavigateNodeSet($node);
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
70 $steps ++;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
71 } elsif ($node->nodeName eq 'SwitchNode') {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
72 # if we are in the switchnode
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
73 # navigate to the target node
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
74 $node = $this->Navigate(sub { $_->name eq $name });
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
75 $steps ++;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
76 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
77
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
78 die IMPL::Exception->new("A node is expected")
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
79 unless $node;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
80 if ($node->nodeName eq 'Node') {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
81 # if we navigate to a reference
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
82 # resolve it
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
83 $node = $this->{$Schema}->resolveType($node->type);
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
84 $this->internalNavigateNodeSet($node);
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
85 $steps++;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
86 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
87
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
88 push @{$this->{$_historySteps}},$steps;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
89
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
90 # return found node schema
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
91 return $node;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
92 } else {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
93 return; # abort navigation
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
94 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
95 #}
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
96 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
97
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
98 sub SchemaBack {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
99 my ($this) = @_;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
100
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
101 $this->Back(pop @{$this->{$_historySteps}}) if $this->{$_historySteps};
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
102 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
103
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
104 sub SourceSchemaNode {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
105 my ($this) = @_;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
106
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
107 if ($this->Current->isa('IMPL::DOM::Schema::SimpleType') or
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
108 $this->Current->isa('IMPL::DOM::Schema::ComplexType')
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
109 ) {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
110 # we are redirected
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
111 return $this->GetNodeFromHistory(-1);
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
112 } else {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
113 return $this->Current;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
114 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
115 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
116
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
117 sub schema {
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
118 goto &Schema;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
119 }
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
120
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
121 1;
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
122 __END__
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
123
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
124 =pod
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
125
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
126 =head1 DESCRIPTION
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
127
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
128 Помимо стандартных методов навигации позволяет переходить по элементам документа,
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
129 который данной схемой описывается.
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
130
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
131 =head1 METHODS
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
132
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
133 =over
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
134
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
135 =item C<NavigateName($name)>
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
136
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
137 Переходит на схему узла с указанным именем. Тоесть использует свойство C<name>.
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
138
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
139 =item C<SchemaBack>
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
140
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
141 Возвращается на позицию до последней операции C<NavigateName>. Данный метод нужен
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
142 посокольку операция навигации по элементам описываемым схемой может приводить к
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
143 нескольким операциям навигации по самой схеме.
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
144
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
145 =item C<SourceSchemaNode>
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
146
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
147 Получает схему узла из которого было выполнено перенаправление, например, C<IMPL::DOM::Schema::Node>.
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
148 В остальных случаях совпадает со свойством C<Current>.
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
149
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
150 =back
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
151
c6e90e02dd17 renamed Lib->lib
cin
parents:
diff changeset
152 =cut