Mercurial > pub > Impl
annotate Lib/IMPL/DOM/Node.pm @ 27:b544a772b654
ORM in progress
author | Sergey |
---|---|
date | Fri, 16 Oct 2009 16:37:53 +0400 |
parents | 7f00786f8210 |
children | dd4d72600c69 |
rev | line source |
---|---|
0 | 1 package IMPL::DOM::Node; |
2 use strict; | |
3 use warnings; | |
4 | |
11 | 5 use base qw(IMPL::Object); |
0 | 6 |
4 | 7 use IMPL::Object::List; |
0 | 8 use IMPL::Class::Property; |
9 use IMPL::Class::Property::Direct; | |
10 use Scalar::Util qw(weaken); | |
11 | |
1 | 12 use IMPL::Exception; |
13 | |
0 | 14 BEGIN { |
4 | 15 public _direct property nodeName => prop_get | owner_set; |
16 public _direct property isComplex => { get => \&_getIsComplex } ; | |
17 public _direct property nodeValue => prop_all; | |
18 public _direct property childNodes => { get => \&_getChildNodes }; | |
19 public _direct property parentNode => prop_get ; | |
18 | 20 public _direct property rootNode => { get => \&_getRootNode}; |
21 private _direct property _propertyMap => prop_all ; | |
0 | 22 } |
23 | |
24 sub CTOR { | |
11 | 25 my ($this,%args) = @_; |
0 | 26 |
11 | 27 $this->nodeName($args{nodeName}) or die new IMPL::InvalidArgumentException("A name is required"); |
18 | 28 $this->nodeValue($args{nodeValue}); |
0 | 29 } |
30 | |
31 sub insertNode { | |
32 my ($this,$node,$pos) = @_; | |
4 | 33 |
34 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; | |
35 | |
36 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
37 | |
38 $this->childNodes->InsertAt($pos,$node); | |
39 | |
40 $node->_setParent( $this ); | |
41 | |
42 return $node; | |
43 } | |
44 | |
14 | 45 sub appendNode { |
16
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
46 my ($this,$node) = @_; |
14 | 47 |
48 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; | |
49 | |
50 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
51 | |
18 | 52 my $children = $this->childNodes; |
53 $children->Append($node); | |
14 | 54 |
55 $node->_setParent( $this ); | |
56 | |
57 return $node; | |
58 } | |
59 | |
16
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
60 sub appendRange { |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
61 my ($this,@range) = @_; |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
62 |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
63 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if grep $_ == $this, @range; |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
64 |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
65 foreach my $node (@range) { |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
66 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
67 $node->_setParent( $this ); |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
68 } |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
69 |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
70 $this->childNodes->Append(@range); |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
71 |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
72 return $this; |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
73 } |
75d55f4ee263
Окончательная концепция описания схем и построения DOM документов
Sergey
parents:
14
diff
changeset
|
74 |
4 | 75 sub _getChildNodes { |
76 my ($this) = @_; | |
77 | |
78 $this->{$childNodes} = new IMPL::Object::List() unless $this->{$childNodes}; | |
18 | 79 return $this->{$childNodes}; |
0 | 80 } |
81 | |
82 sub removeNode { | |
83 my ($this,$node) = @_; | |
4 | 84 |
85 if ($this == $node->{$parentNode}) { | |
86 $this->childNodes->RemoveItem($node); | |
18 | 87 $node->_setParent(undef); |
88 return $node; | |
4 | 89 } else { |
90 die new IMPL::InvalidOperationException("The specified node isn't belong to this node"); | |
91 } | |
0 | 92 } |
93 | |
7 | 94 sub replaceNodeAt { |
95 my ($this,$index,$node) = @_; | |
96 | |
97 my $nodeOld = $this->childNodes->[$index]; | |
98 | |
99 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; | |
100 | |
101 # unlink node from previous parent | |
102 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); | |
103 | |
104 # replace (or set) old node | |
105 $this->childNodes->[$index] = $node; | |
106 | |
18 | 107 # set new parent |
7 | 108 $node->_setParent( $this ); |
109 | |
110 # unlink old node if we have one | |
18 | 111 $nodeOld->_setParent(undef) if $nodeOld; |
7 | 112 |
113 # return old node | |
114 return $nodeOld; | |
115 } | |
116 | |
0 | 117 sub removeAt { |
118 my ($this,$pos) = @_; | |
4 | 119 |
120 if ( my $node = $this->childNodes->RemoveAt($pos) ) { | |
18 | 121 $node->_setParent(undef); |
122 return $node; | |
123 } else { | |
124 return undef; | |
125 } | |
126 } | |
127 | |
128 sub removeLast { | |
129 my ($this) = @_; | |
130 | |
131 if ( my $node = $this->{$childNodes} ? $this->{$childNodes}->RemoveLast() : undef) { | |
132 $node->_setParent(undef); | |
4 | 133 return $node; |
134 } else { | |
135 return undef; | |
136 } | |
0 | 137 } |
138 | |
18 | 139 sub removeSelected { |
140 my ($this,$query) = @_; | |
141 | |
142 my @newSet; | |
143 my @result; | |
144 | |
145 if (ref $query eq 'CODE') { | |
146 &$query($_) ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes}; | |
147 } elsif (defined $query) { | |
148 $_->nodeName eq $query ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes}; | |
149 } else { | |
150 my $children = $this->childNodes; | |
151 $_->_setParent(undef) foreach @$children; | |
152 delete $this->{$childNodes}; | |
153 return wantarray ? @$children : $children; | |
154 } | |
155 | |
156 $_->_setParent(undef) foreach @result; | |
157 | |
158 $this->{$childNodes} = @newSet ? bless \@newSet ,'IMPL::Object::List' : undef; | |
159 | |
160 return wantarray ? @result : \@result; | |
161 } | |
162 | |
0 | 163 sub selectNodes { |
14 | 164 my ($this,$query) = @_; |
18 | 165 |
14 | 166 my @result; |
4 | 167 |
14 | 168 if (ref $query eq 'CODE') { |
169 @result = grep &$query($_), @{$this->childNodes}; | |
24 | 170 } elsif (ref $query eq 'ARRAY' ) { |
171 my %keys = map (($_,1),@$query); | |
172 @result = grep $keys{$_->nodeName}, @{$this->childNodes}; | |
18 | 173 } elsif (defined $query) { |
174 @result = grep $_->nodeName eq $query, @{$this->childNodes}; | |
14 | 175 } else { |
18 | 176 if (wantarray) { |
177 return @{$this->childNodes}; | |
178 } else { | |
179 @result = $this->childNodes; | |
180 return \@result; | |
181 } | |
14 | 182 } |
4 | 183 |
184 return wantarray ? @result : \@result; | |
0 | 185 } |
186 | |
7 | 187 sub firstChild { |
188 @_ >=2 ? $_[0]->replaceNodeAt(0,$_[1]) : $_[0]->childNodes->[0]; | |
189 } | |
190 | |
4 | 191 sub _getIsComplex { |
192 $_[0]->childNodes->Count ? 1 : 0; | |
193 } | |
194 | |
18 | 195 sub _getRootNode { |
196 $_[0]->{$rootNode} || $_[0]; | |
197 } | |
198 | |
199 sub _updateRootRefs { | |
200 my ($this) = @_; | |
201 | |
202 if ( my $newRoot = $this->{$parentNode} ? $this->{$parentNode}->rootNode : undef) { | |
203 if ($this->{$rootNode} ? $this->{$rootNode} != $newRoot : 1 ) { | |
204 $this->{$rootNode} = $newRoot; | |
205 weaken($this->{$rootNode}); | |
206 if ($this->{$childNodes}) { | |
207 $_->_updateRootRefs foreach @{$this->{$childNodes}}; | |
208 } | |
209 } | |
210 } elsif($this->{$rootNode}) { | |
211 delete $this->{$rootNode}; | |
212 if ($this->{$childNodes}) { | |
213 $_->_updateRootRefs foreach @{$this->{$childNodes}}; | |
214 } | |
215 } | |
216 } | |
217 | |
4 | 218 sub _setParent { |
11 | 219 my ($this,$node) = @_; |
4 | 220 |
18 | 221 |
222 if (($node || 0) != ($this->{$parentNode} || 0)) { | |
223 if ($node) { | |
224 $this->{$parentNode} = $node; | |
225 # prevent from creating cyclicreferences | |
226 weaken($this->{$parentNode}); | |
227 } else { | |
228 delete $this->{$parentNode}; | |
229 } | |
230 $this->_updateRootRefs; | |
231 } | |
0 | 232 } |
233 | |
234 sub text { | |
235 my ($this) = @_; | |
4 | 236 |
18 | 237 join '', $this->nodeValue || '', map $_->nodeValue || '', @{$this->childNodes}; |
0 | 238 } |
239 | |
21 | 240 sub nodeProperty { |
0 | 241 my $this = shift; |
242 my $name = shift; | |
243 | |
244 if (@_) { | |
245 # set | |
6 | 246 return $this->{$_propertyMap}{$name} = shift; |
0 | 247 } else { |
6 | 248 return $this->{$_propertyMap}{$name}; |
0 | 249 } |
250 } | |
251 | |
24 | 252 sub qname { |
253 $_[0]->{$nodeName}; | |
254 } | |
255 | |
256 sub path { | |
257 my ($this) = @_; | |
258 | |
259 if ($this->parentNode) { | |
260 return $this->parentNode->path.'.'.$this->qname; | |
261 } else { | |
262 return $this->qname; | |
263 } | |
264 } | |
265 | |
0 | 266 1; |