]> err.no Git - sope/blob - sope-xml/DOM/DOMElement.m
renamed packages as discussed in the developer list
[sope] / sope-xml / DOM / DOMElement.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include <DOM/DOMElement.h>
24 #include <DOM/DOMNamedNodeMap.h>
25 #include <DOM/DOMAttribute.h>
26 #include <DOM/DOMDocument.h>
27 #include <DOM/DOMNodeWalker.h>
28 #include "common.h"
29
30 @interface _DOMElementAttrNamedNodeMap : NSObject < DOMNamedNodeMap >
31 {
32   DOMElement *element; /* non-retained */
33 }
34
35 - (id)initWithElement:(id)_element;
36
37 - (id)objectEnumerator;
38
39 - (void)invalidate;
40
41 @end /* _DOMElementAttrNamedNodeMap */
42
43 @interface DOMElement(Privates)
44 - (unsigned)_numberOfAttributes;
45 - (id)_attributeNodeAtIndex:(unsigned)_idx;
46 - (id)attributeNode:(NSString *)_localName;
47 - (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns;
48 @end
49
50 static NSNull *null = nil;
51
52 @implementation DOMElement
53
54 - (id)initWithTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
55   if (null == nil)
56     null = [[NSNull null] retain];
57   
58   if ((self = [super init])) {
59     self->tagName      = [_tagName copy];
60     self->namespaceURI = [_uri     copy];
61   }
62   return self;
63 }
64 - (id)initWithTagName:(NSString *)_tagName {
65   return [self initWithTagName:_tagName namespaceURI:nil];
66 }
67
68 - (void)dealloc {
69   [self->attributes makeObjectsPerformSelector:
70                       @selector(_domNodeForgetParentNode:)
71                     withObject:self];
72
73   [self->attrNodeMap invalidate];
74   [self->attrNodeMap    release];
75   [self->keyToAttribute release];
76   [self->attributes     release];
77   [self->tagName        release];
78   [self->namespaceURI   release];
79   [self->prefix         release];
80   [super dealloc];
81 }
82
83 /* attributes */
84
85 - (NSString *)tagName {
86   return self->tagName;
87 }
88
89 - (void)setPrefix:(NSString *)_prefix {
90   id old = self->prefix;
91   self->prefix = [_prefix copy];
92   [old release];
93 }
94 - (NSString *)prefix {
95   return self->prefix;
96 }
97
98 - (NSString *)namespaceURI {
99   return self->namespaceURI;
100 }
101
102 - (void)setLine:(unsigned)_line {
103   self->line = _line;
104 }
105 - (unsigned)line {
106   return self->line;
107 }
108
109 /* lookup */
110
111 - (void)_walk_getElementsByTagName:(id)_walker {
112   id node;
113   
114   node = [_walker currentNode];
115   if ([node nodeType] != DOM_ELEMENT_NODE)
116     return;
117
118   if (![[node tagName] isEqualToString:
119           [(NSArray *)[_walker context] objectAtIndex:0]])
120     /* tagname doesn't match */
121     return;
122   
123   [[(NSArray *)[_walker context] objectAtIndex:1] addObject:node];
124 }
125 - (void)_walk_getElementsByTagNameAddAll:(id)_walker {
126   id node;
127   
128   node = [_walker currentNode];
129   if ([node nodeType] != DOM_ELEMENT_NODE)
130     return;
131   
132   [(NSMutableArray *)[_walker context] addObject:node];
133 }
134 - (id)getElementsByTagName:(NSString *)_tagName {
135   /* introduced in DOM2, should return a *live* list ! */
136   NSMutableArray        *array;
137   DOMNodePreorderWalker *walker;
138   SEL sel;
139   id  ctx;
140   
141   if (![self hasChildNodes])
142     return nil;
143
144   if (_tagName == nil)
145     return nil;
146
147   array = [NSMutableArray array];
148   
149   if ([_tagName isEqualToString:@"*"]) {
150     _tagName = nil;
151     ctx = array;
152     sel = @selector(_walk_getElementsByTagNameAddAll:);
153   }
154   else {
155     ctx = [NSArray arrayWithObjects:_tagName, array, nil];
156     sel = @selector(_walk_getElementsByTagName:);
157   }
158   
159   walker = [[DOMNodePreorderWalker alloc]
160                                    initWithTarget:self
161                                    selector:sel
162                                    context:ctx];
163   
164   [walker walkNode:self];
165
166   [walker release]; walker = nil;
167   return [[array copy] autorelease];
168 }
169 - (id)getElementsByTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
170   // TODO: implement
171   [self doesNotRecognizeSelector:_cmd];
172   return nil;
173 }
174
175 /* element attributes */
176
177 - (void)_ensureAttrs {
178   if (self->attributes == nil)
179     self->attributes = [[NSMutableArray alloc] init];
180   if (self->keyToAttribute == nil)
181     self->keyToAttribute = [[NSMutableDictionary alloc] init];
182 }
183
184 - (void)_attributeSetChanged {
185 }
186
187 - (unsigned)_numberOfAttributes {
188   return [self->attributes count];
189 }
190 - (id)_attributeNodeAtIndex:(unsigned)_idx {
191   if (_idx >= [self->attributes count])
192     return nil;
193   return [self->attributes objectAtIndex:_idx];
194 }
195
196 - (id)_keyForAttribute:(id<DOMAttr>)_attrNode {
197   return [_attrNode name];
198 }
199 - (id)_nskeyForLocalName:(NSString *)attrName namespaceURI:(NSString *)nsURI {
200   id key;
201   
202   if (attrName == nil)
203     return nil;
204   
205   if (nsURI) {
206     id objs[2];
207
208     objs[0] = attrName;
209     objs[1] = nsURI;
210     key = [NSArray arrayWithObjects:objs count:2];
211   }
212   else
213     key = attrName;
214   
215   return key;
216 }
217 - (id)_nskeyForAttribute:(id<DOMAttr>)_attrNode {
218   NSString *attrName;
219   
220   if ((attrName = [_attrNode name]) == nil) {
221     NSLog(@"WARNING: attribute %@ has no valid attribute name !", _attrNode);
222     return nil;
223   }
224   
225   return [self _nskeyForLocalName:attrName
226                namespaceURI:[_attrNode namespaceURI]];
227 }
228
229 - (BOOL)hasAttribute:(NSString *)_attrName {
230   return [self hasAttribute:_attrName namespaceURI:[self namespaceURI]];
231 }
232
233 - (void)setAttribute:(NSString *)_attrName value:(NSString *)_value {
234   [self setAttribute:_attrName namespaceURI:[self namespaceURI] value:_value];
235
236 #if 0 // ms: ??
237   id node;
238   
239   NSAssert1(_attrName, @"invalid attribute name '%@'", _attrName);
240
241   if ((node = [self->keyToAttribute objectForKey:_attrName]) == nil) {
242     /* create new node */
243     node = [[self ownerDocument] createAttribute:_attrName];
244   }
245   NSAssert(node, @"couldn't find/create node for attribute");
246
247   node = [self setAttributeNode:node];
248   
249   [node setValue:_value];
250 #endif
251 }
252 - (id)attributeNode:(NSString *)_attrName {
253   return [self attributeNode:_attrName namespaceURI:[self namespaceURI]];
254 }
255 - (NSString *)attribute:(NSString *)_attrName {
256   return [[self attributeNode:_attrName] value];
257 }
258
259 - (BOOL)hasAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
260   id objs[2];
261   id key;
262
263   if ([_ns isEqualToString:@"*"]) {
264     /* match any namespace */
265     NSEnumerator *e;
266     id attr;
267     
268     if ((attr = [self->keyToAttribute objectForKey:_localName]))
269       return YES;
270     
271     e = [self->keyToAttribute keyEnumerator];
272     while ((key = [e nextObject])) {
273       if ([key isKindOfClass:[NSArray class]]) {
274         if ([[key objectAtIndex:0] isEqualToString:_localName])
275           return YES;
276       }
277     }
278     return NO;
279   }
280   
281   objs[0] = _localName;
282   objs[1] = _ns ? _ns : (id)null;
283   key = [NSArray arrayWithObjects:objs count:2];
284   
285   return [self->keyToAttribute objectForKey:key] ? YES : NO;
286 }
287
288 - (void)setAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns
289   value:(NSString *)_value
290 {
291   id key;
292   id node;
293   
294   key = [self _nskeyForLocalName:_localName namespaceURI:_ns];
295   NSAssert2(key, @"invalid (ns-)attribute name localName='%@', uri='%@'",
296             _localName, _ns);
297   
298   if ((node = [self->keyToAttribute objectForKey:key]) == nil) {
299     /* create new node */
300     node = [[self ownerDocument] createAttribute:_localName namespaceURI:_ns];
301   }
302   NSAssert(node, @"couldn't find/create node for attribute");
303
304   node = [self setAttributeNodeNS:node];
305   
306   [node setValue:_value];
307 }
308 - (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns {
309   id objs[2];
310   id key;
311   
312   if ([_ns isEqualToString:@"*"]) {
313     /* match any namespace */
314     NSEnumerator *e;
315     id attr;
316     
317     if ((attr = [self->keyToAttribute objectForKey:_localName]))
318       return attr;
319     
320     e = [self->keyToAttribute keyEnumerator];
321     while ((key = [e nextObject])) {
322       if ([key isKindOfClass:[NSArray class]]) {
323         if ([[key objectAtIndex:0] isEqualToString:_localName])
324           return [self->keyToAttribute objectForKey:key];
325       }
326     }
327     return nil;
328   }
329   
330   objs[0] = _localName;
331   objs[1] = _ns ? _ns : (id)null;
332   key = [NSArray arrayWithObjects:objs count:2];
333
334   return [self->keyToAttribute objectForKey:key];
335 }
336 - (NSString *)attribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
337   return [[self attributeNode:_localName namespaceURI:_ns] value];
338 }
339
340 - (id)setAttributeNodeNS:(id)_attrNode {
341   id key, oldNode;
342   
343   if (_attrNode == nil)
344     /* invalid node parameters */
345     return nil;
346   
347   if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
348     /* couldn't get key */
349     return nil;
350   
351   [self _ensureAttrs];
352   
353   /* check if the key is already added */
354   
355   if ((oldNode = [self->keyToAttribute objectForKey:key])) {
356     if (oldNode == _attrNode) {
357       /* already contained */
358       // NSLog(@"node is already set !");
359       return _attrNode;
360     }
361     
362     /* replace existing node */
363     [self->attributes replaceObjectAtIndex:
364                         [self->attributes indexOfObject:oldNode]
365                       withObject:_attrNode];
366     [self->keyToAttribute setObject:_attrNode forKey:key];
367     
368     [_attrNode _domNodeRegisterParentNode:self];
369     [self _attributeSetChanged];
370
371     return _attrNode;
372   }
373   else {
374     /* add node */
375
376     NSAssert(self->keyToAttribute, @"missing keyToAttribute");
377     NSAssert(self->attributes,     @"missing attrs");
378     
379     [self->keyToAttribute setObject:_attrNode forKey:key];
380     [self->attributes     addObject:_attrNode];
381     
382     [_attrNode _domNodeRegisterParentNode:self];
383     [self _attributeSetChanged];
384
385     // NSLog(@"added attr %@, elem %@", _attrNode, self);
386     
387     return _attrNode;
388   }
389 }
390
391 - (void)removeAttribute:(NSString *)_attr namespaceURI:(NSString *)_uri {
392   id node;
393   id key;
394   
395   key = [self _nskeyForLocalName:_attr namespaceURI:_uri];
396   NSAssert2(key, @"invalid (ns-)attribute name '%@', '%@'", _attr, _uri);
397
398   node = [self->keyToAttribute objectForKey:key];
399   
400   [self removeAttributeNodeNS:node];
401 }
402 - (id)removeAttributeNodeNS:(id)_attrNode {
403   id key, oldNode;
404   
405   if (_attrNode == nil)
406     /* invalid node parameters */
407     return nil;
408   
409   if (self->attributes == nil)
410     /* no attributes are set up */
411     return nil;
412   
413   if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
414     /* couldn't get key for node */
415     return nil;
416
417   if ((oldNode = [self->keyToAttribute objectForKey:key])) {
418     /* the node's key exists */
419     if (oldNode != _attrNode) {
420       /* the node has the same key, but isn't the same */
421       return nil;
422     }
423
424     /* ok, found the node, let's remove ! */
425     [[_attrNode retain] autorelease];
426     [self->keyToAttribute removeObjectForKey:key];
427     [self->attributes removeObjectIdenticalTo:_attrNode];
428     
429     [_attrNode _domNodeForgetParentNode:self];
430     [self _attributeSetChanged];
431     
432     return _attrNode;
433   }
434   else
435     /* no such attribute is stored */
436     return nil;
437 }
438
439 - (id)setAttributeNode:(id)_attrNode {
440   [self doesNotRecognizeSelector:_cmd];
441   return nil;
442 }
443 - (id)removeAttributeNode:(id)_attrNode {
444   [self doesNotRecognizeSelector:_cmd];
445   return nil;
446 }
447 - (void)removeAttribute:(NSString *)_attr {
448   id node;
449   
450   NSAssert1(_attr, @"invalid attribute name '%@'", _attr);
451
452   node = [self->keyToAttribute objectForKey:_attr];
453   
454   [self removeAttributeNode:node];
455 }
456
457 /* node */
458
459 - (BOOL)_isValidChildNode:(id)_node {
460   switch ([_node nodeType]) {
461     case DOM_ELEMENT_NODE:
462     case DOM_TEXT_NODE:
463     case DOM_COMMENT_NODE:
464     case DOM_PROCESSING_INSTRUCTION_NODE:
465     case DOM_CDATA_SECTION_NODE:
466     case DOM_ENTITY_REFERENCE_NODE:
467       return YES;
468       
469     default:
470       return NO;
471   }
472 }
473
474 - (DOMNodeType)nodeType {
475   return DOM_ELEMENT_NODE;
476 }
477
478 - (id)attributes {
479   /* returns a named-node-map */
480   if (self->attrNodeMap == nil) {
481     self->attrNodeMap =
482       [[_DOMElementAttrNamedNodeMap alloc] initWithElement:self];
483   }
484   return self->attrNodeMap;
485 }
486
487 /* parent node */
488
489 - (void)_domNodeRegisterParentNode:(id)_parent {
490   self->parent = _parent;
491 }
492 - (void)_domNodeForgetParentNode:(id)_parent {
493   if (_parent == self->parent)
494     /* the node's parent was deallocated */
495     self->parent = nil;
496 }
497 - (id)parentNode {
498   return self->parent;
499 }
500
501 /* description */
502
503 - (NSString *)description {
504   return [NSString stringWithFormat:
505                      @"<0x%08X[%@]: name=%@ parent=%@ #attrs=%i #children=%i>",
506                      self, NSStringFromClass([self class]),
507                      [self nodeName],
508                      [[self parentNode] nodeName],
509                      [self _numberOfAttributes],
510                      [self hasChildNodes] ? [[self childNodes] length] : 0];
511 }
512
513 @end /* DOMElement */
514
515 @implementation DOMElement(QPValues)
516
517 - (NSException *)setQueryPathValue:(id)_value {
518   return [NSException exceptionWithName:@"QueryPathEvalException"
519                       reason:@"cannot set query-path value on DOMElement !"
520                       userInfo:nil];
521 }
522 - (id)queryPathValue {
523   return [self childNodes];
524 }
525
526 @end /* DOMElement(QPValues) */
527
528 @implementation _DOMElementAttrNamedNodeMap
529
530 - (id)initWithElement:(id)_element {
531   self->element = _element;
532   return self;
533 }
534
535 - (void)invalidate {
536   self->element = nil;
537 }
538
539 static inline void _checkValid(_DOMElementAttrNamedNodeMap *self) {
540   if (self->element == nil) {
541     NSCAssert(self->element,
542               @"named node map is invalid (element was deallocated) !");
543   }
544 }
545
546 /* access */
547
548 static NSString *_XNSUri(NSString *_name) {
549   NSRange r1;
550
551   if (![_name hasPrefix:@"{"])
552     return nil;
553   
554   r1 = [_name rangeOfString:@"}"];
555   if (r1.length == 0)
556     return nil;
557   
558   r1.length   = (r1.location - 2);
559   r1.location = 1;
560   return [_name substringWithRange:r1];
561 }
562 static NSString *_XNSLocalName(NSString *_name) {
563   NSRange r;
564   
565   r = [_name rangeOfString:@"}"];
566   return r.length == 0
567     ? _name
568     : [_name substringFromIndex:(r.location + r.length)];
569 }
570
571 - (unsigned)length {
572   _checkValid(self);
573   return [self->element _numberOfAttributes];
574 }
575 - (id)objectAtIndex:(unsigned)_idx {
576   _checkValid(self);
577   return [self->element _attributeNodeAtIndex:_idx];
578 }
579
580 - (id)namedItem:(NSString *)_name {
581   NSString *nsuri;
582   _checkValid(self);
583   
584   if ((nsuri = _XNSUri(_name)))
585     return [self namedItem:_XNSLocalName(_name) namespaceURI:nsuri];
586   
587   return [self->element attributeNode:_name];
588 }
589 - (id)setNamedItem:(id)_node {
590   _checkValid(self);
591   return [self->element setAttributeNode:_node];
592 }
593 - (id)removeNamedItem:(NSString *)_name {
594   NSString *nsuri;
595   id node;
596   
597   _checkValid(self);
598   if ((nsuri = _XNSUri(_name)))
599     return [self removeNamedItem:_XNSLocalName(_name) namespaceURI:nsuri];
600   
601   if ((node = [self->element attributeNode:_name])) {
602     node = [node retain];
603     [self->element removeAttribute:_name];
604     return [node autorelease];
605   }
606   else
607     return nil;
608 }
609
610 /* DOM2 access */
611
612 - (id)namedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
613   return [self->element attributeNode:_name namespaceURI:_uri];
614 }
615 - (id)setNamedItemNS:(id)_node {
616   _checkValid(self);
617   return [self->element setAttributeNodeNS:_node];
618 }
619 - (id)removeNamedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
620   id node;
621
622   _checkValid(self);
623   if ((node = [self->element attributeNode:_name namespaceURI:_uri])) {
624     node = [node retain];
625     [self->element removeAttribute:_name namespaceURI:_uri];
626     return [node autorelease];
627   }
628   else
629     return nil;
630 }
631
632 /* mimic NSArray */
633
634 - (unsigned)count {
635   _checkValid(self);
636   return [self->element _numberOfAttributes];
637 }
638
639 - (id)objectEnumerator {
640   NSMutableArray *ma;
641   unsigned i, count;
642
643   _checkValid(self);
644   if ((count = [self->element _numberOfAttributes]) == 0)
645     return nil;
646
647   ma = [NSMutableArray arrayWithCapacity:count];
648   
649   for (i = 0; i < count; i++)
650     [ma addObject:[self->element _attributeNodeAtIndex:i]];
651   
652   return [ma objectEnumerator];
653 }
654
655 /* mimic NSDictionary */
656
657 - (void)setObject:(id)_value forKey:(id)_key {
658   _checkValid(self);
659   [self takeValue:_value forKey:[_key stringValue]];
660 }
661 - (id)objectForKey:(id)_key {
662   _checkValid(self);
663   return [self valueForKey:[_key stringValue]];
664 }
665
666 /* KVC */
667
668 - (void)takeValue:(id)_value forKey:(NSString *)_key {
669   id node;
670   _checkValid(self);
671   
672   if ((node = [self->element attributeNode:_key namespaceURI:@"*"])) {
673     [node setValue:[_value stringValue]];
674   }
675   else {
676     [self->element setAttribute:_key namespaceURI:@"xhtml"
677                    value:[_value stringValue]];
678   }
679 }
680 - (id)valueForKey:(NSString *)_key {
681   id v;
682   _checkValid(self);
683   
684   if ((v = [self namedItem:_key]))
685     return [v value];
686   if ((v = [self namedItem:_key namespaceURI:@"*"]))
687     return [v value];
688   
689   return nil;
690 }
691
692 /* JSSupport */
693
694 - (id)_jsprop_length {
695   return [NSNumber numberWithInt:[self length]];
696 }
697
698 - (id)_jsfunc_item:(NSArray *)_args {
699   unsigned count;
700   
701   if ((count = [_args count]) == 0) return nil;
702   return [self objectAtIndex:[[_args objectAtIndex:0] intValue]];
703 }
704
705 - (id)_jsfunc_getNamedItem:(NSArray *)_args {
706   unsigned count;
707   
708   if ((count = [_args count]) == 0) return nil;
709   return [self namedItem:[[_args objectAtIndex:0] stringValue]];
710 }
711 - (id)_jsfunc_getNamedItemNS:(NSArray *)_args {
712   unsigned count;
713   
714   if ((count = [_args count]) == 0) return nil;
715   if (count == 1)
716     return [self namedItem:[[_args objectAtIndex:0] stringValue]];
717   else {
718     return [self namedItem:[[_args objectAtIndex:1] stringValue]
719                  namespaceURI:[[_args objectAtIndex:0] stringValue]];
720   }
721 }
722
723 - (id)_jsfunc_setNamedItem:(NSArray *)_args {
724   unsigned i, count;
725   id last = nil;
726
727   for (i = 0, count = [_args count]; i < count; i++)
728     last = [self setNamedItem:[_args objectAtIndex:i]];
729   return last;
730 }
731 - (id)_jsfunc_setNamedItemNS:(NSArray *)_args {
732   unsigned i, count;
733   id last = nil;
734
735   for (i = 0, count = [_args count]; i < count; i++)
736     last = [self setNamedItemNS:[_args objectAtIndex:i]];
737   return last;
738 }
739
740 - (id)_jsfunc_removeNamedItem:(NSArray *)_args {
741   unsigned count;
742   
743   if ((count = [_args count]) == 0) return nil;
744   return [self namedItem:[[_args objectAtIndex:0] stringValue]];
745 }
746 - (id)_jsfunc_removeNamedItemNS:(NSArray *)_args {
747   unsigned count;
748   
749   if ((count = [_args count]) == 0) return nil;
750   if (count == 1)
751     return [self removeNamedItem:[[_args objectAtIndex:0] stringValue]];
752   else {
753     return [self removeNamedItem:[[_args objectAtIndex:1] stringValue]
754                  namespaceURI:[[_args objectAtIndex:0] stringValue]];
755   }
756 }
757
758 /* description */
759
760 - (NSString *)description {
761   NSMutableString *ms;
762   NSEnumerator *e;
763   id attr;
764   
765   ms = [NSMutableString stringWithCapacity:1024];
766   [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
767   [ms appendFormat:@" element=%@", self->element];
768   
769   [ms appendString:@" attributes:\n"];
770   e = [self objectEnumerator];
771   while ((attr = [e nextObject])) {
772     [ms appendString:[attr description]];
773     [ms appendString:@"\n"];
774   }
775   
776   [ms appendString:@">"];
777   return ms;
778 }
779
780 @end /* _DOMElementAttrNamedNodeMap */