comparison Lib/IMPL/DOM/Node.pm @ 18:818c74b038ae

DOM Schema + tests
author Sergey
date Thu, 10 Sep 2009 17:42:47 +0400
parents 75d55f4ee263
children fafe56cfcd69
comparison
equal deleted inserted replaced
17:7f88e01b58f8 18:818c74b038ae
15 public _direct property nodeName => prop_get | owner_set; 15 public _direct property nodeName => prop_get | owner_set;
16 public _direct property isComplex => { get => \&_getIsComplex } ; 16 public _direct property isComplex => { get => \&_getIsComplex } ;
17 public _direct property nodeValue => prop_all; 17 public _direct property nodeValue => prop_all;
18 public _direct property childNodes => { get => \&_getChildNodes }; 18 public _direct property childNodes => { get => \&_getChildNodes };
19 public _direct property parentNode => prop_get ; 19 public _direct property parentNode => prop_get ;
20 private _direct property _propertyMap => prop_get ; 20 public _direct property rootNode => { get => \&_getRootNode};
21 private _direct property _propertyMap => prop_all ;
21 } 22 }
22 23
23 sub CTOR { 24 sub CTOR {
24 my ($this,%args) = @_; 25 my ($this,%args) = @_;
25 26
26 $this->nodeName($args{nodeName}) or die new IMPL::InvalidArgumentException("A name is required"); 27 $this->nodeName($args{nodeName}) or die new IMPL::InvalidArgumentException("A name is required");
28 $this->nodeValue($args{nodeValue});
27 } 29 }
28 30
29 sub insertNode { 31 sub insertNode {
30 my ($this,$node,$pos) = @_; 32 my ($this,$node,$pos) = @_;
31 33
45 47
46 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node; 48 die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
47 49
48 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); 50 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
49 51
50 $this->childNodes->Append($node); 52 my $children = $this->childNodes;
53 $children->Append($node);
51 54
52 $node->_setParent( $this ); 55 $node->_setParent( $this );
53 56
54 return $node; 57 return $node;
55 } 58 }
71 74
72 sub _getChildNodes { 75 sub _getChildNodes {
73 my ($this) = @_; 76 my ($this) = @_;
74 77
75 $this->{$childNodes} = new IMPL::Object::List() unless $this->{$childNodes}; 78 $this->{$childNodes} = new IMPL::Object::List() unless $this->{$childNodes};
76 $this->{$childNodes}; 79 return $this->{$childNodes};
77 } 80 }
78 81
79 sub removeNode { 82 sub removeNode {
80 my ($this,$node) = @_; 83 my ($this,$node) = @_;
81 84
82 if ($this == $node->{$parentNode}) { 85 if ($this == $node->{$parentNode}) {
83 $this->childNodes->RemoveItem($node); 86 $this->childNodes->RemoveItem($node);
84 $node->{$parentNode} = undef; 87 $node->_setParent(undef);
85 return $this; 88 return $node;
86 } else { 89 } else {
87 die new IMPL::InvalidOperationException("The specified node isn't belong to this node"); 90 die new IMPL::InvalidOperationException("The specified node isn't belong to this node");
88 } 91 }
89 } 92 }
90 93
99 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode}); 102 $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
100 103
101 # replace (or set) old node 104 # replace (or set) old node
102 $this->childNodes->[$index] = $node; 105 $this->childNodes->[$index] = $node;
103 106
104 # save new parent 107 # set new parent
105 $node->_setParent( $this ); 108 $node->_setParent( $this );
106 109
107 # unlink old node if we have one 110 # unlink old node if we have one
108 $nodeOld->{$parentNode} = undef if $nodeOld; 111 $nodeOld->_setParent(undef) if $nodeOld;
109 112
110 # return old node 113 # return old node
111 return $nodeOld; 114 return $nodeOld;
112 } 115 }
113 116
114 sub removeAt { 117 sub removeAt {
115 my ($this,$pos) = @_; 118 my ($this,$pos) = @_;
116 119
117 if ( my $node = $this->childNodes->RemoveAt($pos) ) { 120 if ( my $node = $this->childNodes->RemoveAt($pos) ) {
118 $node->{$parentNode} = undef; 121 $node->_setParent(undef);
119 return $node; 122 return $node;
120 } else { 123 } else {
121 return undef; 124 return undef;
122 } 125 }
126 }
127
128 sub removeLast {
129 my ($this) = @_;
130
131 if ( my $node = $this->{$childNodes} ? $this->{$childNodes}->RemoveLast() : undef) {
132 $node->_setParent(undef);
133 return $node;
134 } else {
135 return undef;
136 }
137 }
138
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;
123 } 161 }
124 162
125 sub selectNodes { 163 sub selectNodes {
126 my ($this,$query) = @_; 164 my ($this,$query) = @_;
165
127 my @result; 166 my @result;
128 167
129 if (ref $query eq 'CODE') { 168 if (ref $query eq 'CODE') {
130 @result = grep &$query($_), @{$this->childNodes}; 169 @result = grep &$query($_), @{$this->childNodes};
131 } else { 170 } elsif (defined $query) {
132 @result = grep $_->nodeName eq $query, @{$this->childNodes}; 171 @result = grep $_->nodeName eq $query, @{$this->childNodes};
172 } else {
173 if (wantarray) {
174 return @{$this->childNodes};
175 } else {
176 @result = $this->childNodes;
177 return \@result;
178 }
133 } 179 }
134 180
135 return wantarray ? @result : \@result; 181 return wantarray ? @result : \@result;
136 } 182 }
137 183
141 187
142 sub _getIsComplex { 188 sub _getIsComplex {
143 $_[0]->childNodes->Count ? 1 : 0; 189 $_[0]->childNodes->Count ? 1 : 0;
144 } 190 }
145 191
192 sub _getRootNode {
193 $_[0]->{$rootNode} || $_[0];
194 }
195
196 sub _updateRootRefs {
197 my ($this) = @_;
198
199 if ( my $newRoot = $this->{$parentNode} ? $this->{$parentNode}->rootNode : undef) {
200 if ($this->{$rootNode} ? $this->{$rootNode} != $newRoot : 1 ) {
201 $this->{$rootNode} = $newRoot;
202 weaken($this->{$rootNode});
203 if ($this->{$childNodes}) {
204 $_->_updateRootRefs foreach @{$this->{$childNodes}};
205 }
206 }
207 } elsif($this->{$rootNode}) {
208 delete $this->{$rootNode};
209 if ($this->{$childNodes}) {
210 $_->_updateRootRefs foreach @{$this->{$childNodes}};
211 }
212 }
213 }
214
146 sub _setParent { 215 sub _setParent {
147 my ($this,$node) = @_; 216 my ($this,$node) = @_;
148 217
149 $this->{$parentNode} = $node; 218
150 # prevent from creating cyclicreferences 219 if (($node || 0) != ($this->{$parentNode} || 0)) {
151 weaken($this->{$parentNode}); 220 if ($node) {
221 $this->{$parentNode} = $node;
222 # prevent from creating cyclicreferences
223 weaken($this->{$parentNode});
224 } else {
225 delete $this->{$parentNode};
226 }
227 $this->_updateRootRefs;
228 }
152 } 229 }
153 230
154 sub text { 231 sub text {
155 my ($this) = @_; 232 my ($this) = @_;
156 233
157 join '', $this->nodeValue, map $_->nodeValue, @{$this->childNodes}; 234 join '', $this->nodeValue || '', map $_->nodeValue || '', @{$this->childNodes};
158 } 235 }
159 236
160 sub Property { 237 sub Property {
161 my $this = shift; 238 my $this = shift;
162 my $name = shift; 239 my $name = shift;