comparison Lib/IMPL/DOM/Schema/Validator/Compare.pm @ 194:4d0e1962161c

Replaced tabs with spaces IMPL::Web::View - fixed document model, new features (control classes, document constructor parameters)
author cin
date Tue, 10 Apr 2012 20:08:29 +0400
parents d1676be8afcc
children 2904da230022
comparison
equal deleted inserted replaced
193:8e8401c0aea4 194:4d0e1962161c
5 5
6 use IMPL::Resources::Format qw(FormatMessage); 6 use IMPL::Resources::Format qw(FormatMessage);
7 use IMPL::Class::Property; 7 use IMPL::Class::Property;
8 8
9 BEGIN { 9 BEGIN {
10 public property targetProperty => prop_all; 10 public property targetProperty => prop_all;
11 public property op => prop_all; 11 public property op => prop_all;
12 public property nodePath => prop_all; 12 public property nodePath => prop_all;
13 public property optional => prop_all; 13 public property optional => prop_all;
14 private property _pathTranslated => prop_all; 14 private property _pathTranslated => prop_all;
15 private property _targetNode => prop_all; 15 private property _targetNode => prop_all;
16 public property message => prop_all; 16 public property message => prop_all;
17 } 17 }
18 18
19 our %CTOR = ( 19 our %CTOR = (
20 'IMPL::DOM::Schema::Validator' => sub { 20 'IMPL::DOM::Schema::Validator' => sub {
21 my %args = @_; 21 my %args = @_;
22 $args{nodeName} ||= 'Compare'; 22 $args{nodeName} ||= 'Compare';
23 delete @args{qw(targetProperty op nodePath optional message)}; 23 delete @args{qw(targetProperty op nodePath optional message)};
24 %args; 24 %args;
25 } 25 }
26 ); 26 );
27 27
28 our %Ops = ( 28 our %Ops = (
29 '=' => \&_equals, 29 '=' => \&_equals,
30 'eq' => \&_equalsString, 30 'eq' => \&_equalsString,
31 '!=' => \&_notEquals, 31 '!=' => \&_notEquals,
32 'ne' => \&_notEqualsString, 32 'ne' => \&_notEqualsString,
33 '=~' => \&_matchRx, 33 '=~' => \&_matchRx,
34 '!~' => \&_notMatchRx, 34 '!~' => \&_notMatchRx,
35 '<' => \&_less, 35 '<' => \&_less,
36 '>' => \&_greater, 36 '>' => \&_greater,
37 'lt' => \&_lessString, 37 'lt' => \&_lessString,
38 'gt' => \&_greaterString 38 'gt' => \&_greaterString
39 ); 39 );
40 40
41 my $rxOps = map qr/$_/, join( '|', keys %Ops ); 41 my $rxOps = map qr/$_/, join( '|', keys %Ops );
42 42
43 sub CTOR { 43 sub CTOR {
44 my ($this,%args) = @_; 44 my ($this,%args) = @_;
45 45
46 $this->targetProperty($args{targetProperty} || 'nodeValue'); 46 $this->targetProperty($args{targetProperty} || 'nodeValue');
47 $this->op( $Ops{ $args{op} || '=' } ) or die new IMPL::InvalidArgumentException("Invalid parameter value",'op',$args{op},$this->path); 47 $this->op( $Ops{ $args{op} || '=' } ) or die new IMPL::InvalidArgumentException("Invalid parameter value",'op',$args{op},$this->path);
48 $this->nodePath($args{nodePath}) or die new IMPL::InvalidArgumentException("The argument is required", 'nodePath', $this->path); 48 $this->nodePath($args{nodePath}) or die new IMPL::InvalidArgumentException("The argument is required", 'nodePath', $this->path);
49 $this->message($args{message} || 'The value of %Node.path% %Source.op% %Value% (%Source.nodePath%)' ); 49 $this->message($args{message} || 'The value of %Node.path% %Source.op% %Value% (%Source.nodePath%)' );
50 $this->optional($args{optional}) if $args{optional}; 50 $this->optional($args{optional}) if $args{optional};
51 } 51 }
52 52
53 sub TranslatePath { 53 sub TranslatePath {
54 my ($this,$path) = @_; 54 my ($this,$path) = @_;
55 55
56 $path ||= ''; 56 $path ||= '';
57 57
58 my @selectQuery; 58 my @selectQuery;
59 59
60 my $i = 0; 60 my $i = 0;
61 61
62 foreach my $chunk (split /\//,$path) { 62 foreach my $chunk (split /\//,$path) {
63 $chunk = 'document:*' if $i == 0 and not length $chunk; 63 $chunk = 'document:*' if $i == 0 and not length $chunk;
64 next if not length $chunk; 64 next if not length $chunk;
65 65
66 my $query; 66 my $query;
67 my ($axis,$filter) = ( $chunk =~ /^(?:(\w+):)?(.*)$/); 67 my ($axis,$filter) = ( $chunk =~ /^(?:(\w+):)?(.*)$/);
68 68
69 if ($filter =~ /^\w+|\*$/ ) { 69 if ($filter =~ /^\w+|\*$/ ) {
70 $query = $filter eq '*' ? undef : $filter; 70 $query = $filter eq '*' ? undef : $filter;
71 } elsif ( $filter =~ /^(\w+|\*)\s*((?:\[\s*\w+\s*(?:=|!=|=~|!~|eq|ne|lt|gt|)\s*["'](?:[\\'"]|\\[\\"'])*["']\])+)$/) { 71 } elsif ( $filter =~ /^(\w+|\*)\s*((?:\[\s*\w+\s*(?:=|!=|=~|!~|eq|ne|lt|gt|)\s*["'](?:[\\'"]|\\[\\"'])*["']\])+)$/) {
72 my ($nodeName,$filterArgs) = ($1,$2); 72 my ($nodeName,$filterArgs) = ($1,$2);
73 73
74 my @parsedFilters = map { 74 my @parsedFilters = map {
75 my ($prop,$op,$value) = ($_ =~ /\s*(\w+)\s*(=|!=|=~|!~)\s*(["'](?:[\\'"]|\\[\\"'])*["'])/); 75 my ($prop,$op,$value) = ($_ =~ /\s*(\w+)\s*(=|!=|=~|!~)\s*(["'](?:[\\'"]|\\[\\"'])*["'])/);
76 $value =~ s/\\[\\'"]/$1/g; 76 $value =~ s/\\[\\'"]/$1/g;
77 { 77 {
78 prop => $prop, 78 prop => $prop,
79 op => $Ops{$op}, 79 op => $Ops{$op},
80 value => $value 80 value => $value
81 } 81 }
82 } grep ( $_, split ( /[\]\[]+/,$filterArgs ) ); 82 } grep ( $_, split ( /[\]\[]+/,$filterArgs ) );
83 83
84 $query = sub { 84 $query = sub {
85 my ($node) = shift; 85 my ($node) = shift;
86 86
87 $node->nodeName eq $nodeName or return 0 if $nodeName ne '*'; 87 $node->nodeName eq $nodeName or return 0 if $nodeName ne '*';
88 $_->{op}->( 88 $_->{op}->(
89 _resovleProperty($node,$_->{prop}), 89 _resovleProperty($node,$_->{prop}),
90 FormatMessage($_->{value},{ 90 FormatMessage($_->{value},{
91 Schema => $this->parentNode, 91 Schema => $this->parentNode,
92 Node => $this->_targetNode 92 Node => $this->_targetNode
93 },\&_resovleProperty) 93 },\&_resovleProperty)
94 ) or return 0 foreach @parsedFilters; 94 ) or return 0 foreach @parsedFilters;
95 95
96 }; 96 };
97 } else { 97 } else {
98 die new IMPL::Exception("Invalid query syntax",$path,$chunk); 98 die new IMPL::Exception("Invalid query syntax",$path,$chunk);
99 } 99 }
100 100
101 push @selectQuery, $axis ? { $axis => $query } : $query; 101 push @selectQuery, $axis ? { $axis => $query } : $query;
102 102
103 $i++; 103 $i++;
104 } 104 }
105 105
106 return \@selectQuery; 106 return \@selectQuery;
107 } 107 }
108 108
109 sub Validate { 109 sub Validate {
110 my ($this,$node,$ctx) = @_; 110 my ($this,$node,$ctx) = @_;
111 111
112 my @result; 112 my @result;
113 113
114 $this->_targetNode($node); 114 $this->_targetNode($node);
115 115
116 my $query = $this->_pathTranslated() || $this->_pathTranslated($this->TranslatePath($this->nodePath)); 116 my $query = $this->_pathTranslated() || $this->_pathTranslated($this->TranslatePath($this->nodePath));
117 117
118 my ($foreignNode) = $node->selectNodes(@$query); 118 my ($foreignNode) = $node->selectNodes(@$query);
119 119
120 my $Source = $ctx && $ctx->{Source} || $this->parentNode; 120 my $Source = $ctx && $ctx->{Source} || $this->parentNode;
121 121
122 if ($foreignNode) { 122 if ($foreignNode) {
123 my $value = $this->nodeValue; 123 my $value = $this->nodeValue;
124 124
125 if ($value) { 125 if ($value) {
126 $value = FormatMessage($value, { Schema => $this->parentNode, Node => $this->_targetNode, ForeignNode => $foreignNode },\&_resovleProperty); 126 $value = FormatMessage($value, { Schema => $this->parentNode, Node => $this->_targetNode, ForeignNode => $foreignNode },\&_resovleProperty);
127 } else { 127 } else {
128 $value = $foreignNode->nodeValue; 128 $value = $foreignNode->nodeValue;
129 } 129 }
130 130
131 push @result, new IMPL::DOM::Schema::ValidationError( 131 push @result, new IMPL::DOM::Schema::ValidationError(
132 Node => $node, 132 Node => $node,
133 ForeignNode => $foreignNode, 133 ForeignNode => $foreignNode,
134 Value => $value, 134 Value => $value,
135 Source => $Source, 135 Source => $Source,
136 Schema => $this->parentNode, 136 Schema => $this->parentNode,
137 Message => $this->message 137 Message => $this->message
138 ) unless $this->op->(_resovleProperty($node,$this->targetProperty),$value); 138 ) unless $this->op->(_resovleProperty($node,$this->targetProperty),$value);
139 } elsif (not $this->optional) { 139 } elsif (not $this->optional) {
140 push @result, new IMPL::DOM::Schema::ValidationError( 140 push @result, new IMPL::DOM::Schema::ValidationError(
141 Node => $node, 141 Node => $node,
142 Value => '', 142 Value => '',
143 Source => $Source, 143 Source => $Source,
144 Schema => $this->parentNode, 144 Schema => $this->parentNode,
145 Message => $this->message 145 Message => $this->message
146 ); 146 );
147 } 147 }
148 148
149 $this->_targetNode(undef); 149 $this->_targetNode(undef);
150 150
151 return @result; 151 return @result;
152 } 152 }
153 153
154 sub _resovleProperty { 154 sub _resovleProperty {
155 my ($node,$prop) = @_; 155 my ($node,$prop) = @_;
156 156
157 return $node->can($prop) ? $node->$prop() : $node->nodeProperty($prop); 157 return $node->can($prop) ? $node->$prop() : $node->nodeProperty($prop);
158 } 158 }
159 159
160 sub _matchRx { 160 sub _matchRx {
161 $_[0] =~ $_[1]; 161 $_[0] =~ $_[1];
162 } 162 }
163 163
164 sub _notMatchRx { 164 sub _notMatchRx {
165 $_[0] !~ $_[1]; 165 $_[0] !~ $_[1];
166 } 166 }
167 167
168 sub _equals { 168 sub _equals {
169 $_[0] == $_[1]; 169 $_[0] == $_[1];
170 } 170 }
171 171
172 sub _notEquals { 172 sub _notEquals {
173 $_[0] != $_[0]; 173 $_[0] != $_[0];
174 } 174 }
175 175
176 sub _equalsString { 176 sub _equalsString {
177 $_[0] eq $_[1]; 177 $_[0] eq $_[1];
178 } 178 }
179 179
180 sub _notEqualsString { 180 sub _notEqualsString {
181 $_[0] ne $_[1]; 181 $_[0] ne $_[1];
182 } 182 }
183 183
184 sub _less { 184 sub _less {
185 $_[0] < $_[1]; 185 $_[0] < $_[1];
186 } 186 }
187 187
188 sub _greater { 188 sub _greater {
189 $_[0] > $_[1]; 189 $_[0] > $_[1];
190 } 190 }
191 191
192 sub _lessString { 192 sub _lessString {
193 $_[0] lt $_[1]; 193 $_[0] lt $_[1];
194 } 194 }
195 195
196 sub _greaterString { 196 sub _greaterString {
197 $_[0] gt $_[1]; 197 $_[0] gt $_[1];
198 } 198 }
199 199
200 sub _lessEq { 200 sub _lessEq {
201 $_[0] <= $_[1]; 201 $_[0] <= $_[1];
202 } 202 }
203 203
204 sub _greaterEq { 204 sub _greaterEq {
205 $_[0] >= $_[1]; 205 $_[0] >= $_[1];
206 } 206 }
207 207
208 1; 208 1;
209 209
210 __END__ 210 __END__
221 Пример типа описания поля с проверочным полем 221 Пример типа описания поля с проверочным полем
222 222
223 =begin code xml 223 =begin code xml
224 224
225 <schema> 225 <schema>
226 <SimpleType type="retype_field"> 226 <SimpleType type="retype_field">
227 <Property name="linkedNode" message="Для узла %Node.nodeName% необходимо задать свойство %Source.name%"/> 227 <Property name="linkedNode" message="Для узла %Node.nodeName% необходимо задать свойство %Source.name%"/>
228 <Compare op="eq" nodePath="sibling:*[nodeName eq '%Node.linkedNode%']"/> 228 <Compare op="eq" nodePath="sibling:*[nodeName eq '%Node.linkedNode%']"/>
229 </SimpleType> 229 </SimpleType>
230 </schema> 230 </schema>
231 231
232 =begin code xml 232 =begin code xml
233 233
234 =head1 DESCRIPTION 234 =head1 DESCRIPTION