Mercurial > pub > Impl
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 |