2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
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.
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
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>
30 @interface _DOMElementAttrNamedNodeMap : NSObject < DOMNamedNodeMap >
32 DOMElement *element; /* non-retained */
35 - (id)initWithElement:(id)_element;
37 - (id)objectEnumerator;
41 @end /* _DOMElementAttrNamedNodeMap */
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;
50 static NSNull *null = nil;
52 @implementation DOMElement
54 - (id)initWithTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
56 null = [[NSNull null] retain];
58 if ((self = [super init])) {
59 self->tagName = [_tagName copy];
60 self->namespaceURI = [_uri copy];
64 - (id)initWithTagName:(NSString *)_tagName {
65 return [self initWithTagName:_tagName namespaceURI:nil];
69 [self->attributes makeObjectsPerformSelector:
70 @selector(_domNodeForgetParentNode:)
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];
85 - (NSString *)tagName {
89 - (void)setPrefix:(NSString *)_prefix {
90 id old = self->prefix;
91 self->prefix = [_prefix copy];
94 - (NSString *)prefix {
98 - (NSString *)namespaceURI {
99 return self->namespaceURI;
102 - (void)setLine:(unsigned)_line {
111 - (void)_walk_getElementsByTagName:(id)_walker {
114 node = [_walker currentNode];
115 if ([node nodeType] != DOM_ELEMENT_NODE)
118 if (![[node tagName] isEqualToString:
119 [(NSArray *)[_walker context] objectAtIndex:0]])
120 /* tagname doesn't match */
123 [[(NSArray *)[_walker context] objectAtIndex:1] addObject:node];
125 - (void)_walk_getElementsByTagNameAddAll:(id)_walker {
128 node = [_walker currentNode];
129 if ([node nodeType] != DOM_ELEMENT_NODE)
132 [(NSMutableArray *)[_walker context] addObject:node];
134 - (id)getElementsByTagName:(NSString *)_tagName {
135 /* introduced in DOM2, should return a *live* list ! */
136 NSMutableArray *array;
137 DOMNodePreorderWalker *walker;
141 if (![self hasChildNodes])
147 array = [NSMutableArray array];
149 if ([_tagName isEqualToString:@"*"]) {
152 sel = @selector(_walk_getElementsByTagNameAddAll:);
155 ctx = [NSArray arrayWithObjects:_tagName, array, nil];
156 sel = @selector(_walk_getElementsByTagName:);
159 walker = [[DOMNodePreorderWalker alloc]
164 [walker walkNode:self];
166 [walker release]; walker = nil;
167 return [[array copy] autorelease];
169 - (id)getElementsByTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
171 [self doesNotRecognizeSelector:_cmd];
175 /* element attributes */
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];
184 - (void)_attributeSetChanged {
187 - (unsigned)_numberOfAttributes {
188 return [self->attributes count];
190 - (id)_attributeNodeAtIndex:(unsigned)_idx {
191 if (_idx >= [self->attributes count])
193 return [self->attributes objectAtIndex:_idx];
196 - (id)_keyForAttribute:(id<DOMAttr>)_attrNode {
197 return [_attrNode name];
199 - (id)_nskeyForLocalName:(NSString *)attrName namespaceURI:(NSString *)nsURI {
210 key = [NSArray arrayWithObjects:objs count:2];
217 - (id)_nskeyForAttribute:(id<DOMAttr>)_attrNode {
220 if ((attrName = [_attrNode name]) == nil) {
221 NSLog(@"WARNING: attribute %@ has no valid attribute name !", _attrNode);
225 return [self _nskeyForLocalName:attrName
226 namespaceURI:[_attrNode namespaceURI]];
229 - (BOOL)hasAttribute:(NSString *)_attrName {
230 return [self hasAttribute:_attrName namespaceURI:[self namespaceURI]];
233 - (void)setAttribute:(NSString *)_attrName value:(NSString *)_value {
234 [self setAttribute:_attrName namespaceURI:[self namespaceURI] value:_value];
239 NSAssert1(_attrName, @"invalid attribute name '%@'", _attrName);
241 if ((node = [self->keyToAttribute objectForKey:_attrName]) == nil) {
242 /* create new node */
243 node = [[self ownerDocument] createAttribute:_attrName];
245 NSAssert(node, @"couldn't find/create node for attribute");
247 node = [self setAttributeNode:node];
249 [node setValue:_value];
252 - (id)attributeNode:(NSString *)_attrName {
253 return [self attributeNode:_attrName namespaceURI:[self namespaceURI]];
255 - (NSString *)attribute:(NSString *)_attrName {
256 return [[self attributeNode:_attrName] value];
259 - (BOOL)hasAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
263 if ([_ns isEqualToString:@"*"]) {
264 /* match any namespace */
268 if ((attr = [self->keyToAttribute objectForKey:_localName]))
271 e = [self->keyToAttribute keyEnumerator];
272 while ((key = [e nextObject])) {
273 if ([key isKindOfClass:[NSArray class]]) {
274 if ([[key objectAtIndex:0] isEqualToString:_localName])
281 objs[0] = _localName;
282 objs[1] = _ns ? _ns : (id)null;
283 key = [NSArray arrayWithObjects:objs count:2];
285 return [self->keyToAttribute objectForKey:key] ? YES : NO;
288 - (void)setAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns
289 value:(NSString *)_value
294 key = [self _nskeyForLocalName:_localName namespaceURI:_ns];
295 NSAssert2(key, @"invalid (ns-)attribute name localName='%@', uri='%@'",
298 if ((node = [self->keyToAttribute objectForKey:key]) == nil) {
299 /* create new node */
300 node = [[self ownerDocument] createAttribute:_localName namespaceURI:_ns];
302 NSAssert(node, @"couldn't find/create node for attribute");
304 node = [self setAttributeNodeNS:node];
306 [node setValue:_value];
308 - (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns {
312 if ([_ns isEqualToString:@"*"]) {
313 /* match any namespace */
317 if ((attr = [self->keyToAttribute objectForKey:_localName]))
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];
330 objs[0] = _localName;
331 objs[1] = _ns ? _ns : (id)null;
332 key = [NSArray arrayWithObjects:objs count:2];
334 return [self->keyToAttribute objectForKey:key];
336 - (NSString *)attribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
337 return [[self attributeNode:_localName namespaceURI:_ns] value];
340 - (id)setAttributeNodeNS:(id)_attrNode {
343 if (_attrNode == nil)
344 /* invalid node parameters */
347 if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
348 /* couldn't get key */
353 /* check if the key is already added */
355 if ((oldNode = [self->keyToAttribute objectForKey:key])) {
356 if (oldNode == _attrNode) {
357 /* already contained */
358 // NSLog(@"node is already set !");
362 /* replace existing node */
363 [self->attributes replaceObjectAtIndex:
364 [self->attributes indexOfObject:oldNode]
365 withObject:_attrNode];
366 [self->keyToAttribute setObject:_attrNode forKey:key];
368 [_attrNode _domNodeRegisterParentNode:self];
369 [self _attributeSetChanged];
376 NSAssert(self->keyToAttribute, @"missing keyToAttribute");
377 NSAssert(self->attributes, @"missing attrs");
379 [self->keyToAttribute setObject:_attrNode forKey:key];
380 [self->attributes addObject:_attrNode];
382 [_attrNode _domNodeRegisterParentNode:self];
383 [self _attributeSetChanged];
385 // NSLog(@"added attr %@, elem %@", _attrNode, self);
391 - (void)removeAttribute:(NSString *)_attr namespaceURI:(NSString *)_uri {
395 key = [self _nskeyForLocalName:_attr namespaceURI:_uri];
396 NSAssert2(key, @"invalid (ns-)attribute name '%@', '%@'", _attr, _uri);
398 node = [self->keyToAttribute objectForKey:key];
400 [self removeAttributeNodeNS:node];
402 - (id)removeAttributeNodeNS:(id)_attrNode {
405 if (_attrNode == nil)
406 /* invalid node parameters */
409 if (self->attributes == nil)
410 /* no attributes are set up */
413 if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
414 /* couldn't get key for node */
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 */
424 /* ok, found the node, let's remove ! */
425 [[_attrNode retain] autorelease];
426 [self->keyToAttribute removeObjectForKey:key];
427 [self->attributes removeObjectIdenticalTo:_attrNode];
429 [_attrNode _domNodeForgetParentNode:self];
430 [self _attributeSetChanged];
435 /* no such attribute is stored */
439 - (id)setAttributeNode:(id)_attrNode {
440 [self doesNotRecognizeSelector:_cmd];
443 - (id)removeAttributeNode:(id)_attrNode {
444 [self doesNotRecognizeSelector:_cmd];
447 - (void)removeAttribute:(NSString *)_attr {
450 NSAssert1(_attr, @"invalid attribute name '%@'", _attr);
452 node = [self->keyToAttribute objectForKey:_attr];
454 [self removeAttributeNode:node];
459 - (BOOL)_isValidChildNode:(id)_node {
460 switch ([_node nodeType]) {
461 case DOM_ELEMENT_NODE:
463 case DOM_COMMENT_NODE:
464 case DOM_PROCESSING_INSTRUCTION_NODE:
465 case DOM_CDATA_SECTION_NODE:
466 case DOM_ENTITY_REFERENCE_NODE:
474 - (DOMNodeType)nodeType {
475 return DOM_ELEMENT_NODE;
479 /* returns a named-node-map */
480 if (self->attrNodeMap == nil) {
482 [[_DOMElementAttrNamedNodeMap alloc] initWithElement:self];
484 return self->attrNodeMap;
489 - (void)_domNodeRegisterParentNode:(id)_parent {
490 self->parent = _parent;
492 - (void)_domNodeForgetParentNode:(id)_parent {
493 if (_parent == self->parent)
494 /* the node's parent was deallocated */
503 - (NSString *)description {
504 return [NSString stringWithFormat:
505 @"<0x%08X[%@]: name=%@ parent=%@ #attrs=%i #children=%i>",
506 self, NSStringFromClass([self class]),
508 [[self parentNode] nodeName],
509 [self _numberOfAttributes],
510 [self hasChildNodes] ? [[self childNodes] length] : 0];
513 @end /* DOMElement */
515 @implementation DOMElement(QPValues)
517 - (NSException *)setQueryPathValue:(id)_value {
518 return [NSException exceptionWithName:@"QueryPathEvalException"
519 reason:@"cannot set query-path value on DOMElement !"
522 - (id)queryPathValue {
523 return [self childNodes];
526 @end /* DOMElement(QPValues) */
528 @implementation _DOMElementAttrNamedNodeMap
530 - (id)initWithElement:(id)_element {
531 self->element = _element;
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) !");
548 static NSString *_XNSUri(NSString *_name) {
551 if (![_name hasPrefix:@"{"])
554 r1 = [_name rangeOfString:@"}"];
558 r1.length = (r1.location - 2);
560 return [_name substringWithRange:r1];
562 static NSString *_XNSLocalName(NSString *_name) {
565 r = [_name rangeOfString:@"}"];
568 : [_name substringFromIndex:(r.location + r.length)];
573 return [self->element _numberOfAttributes];
575 - (id)objectAtIndex:(unsigned)_idx {
577 return [self->element _attributeNodeAtIndex:_idx];
580 - (id)namedItem:(NSString *)_name {
584 if ((nsuri = _XNSUri(_name)))
585 return [self namedItem:_XNSLocalName(_name) namespaceURI:nsuri];
587 return [self->element attributeNode:_name];
589 - (id)setNamedItem:(id)_node {
591 return [self->element setAttributeNode:_node];
593 - (id)removeNamedItem:(NSString *)_name {
598 if ((nsuri = _XNSUri(_name)))
599 return [self removeNamedItem:_XNSLocalName(_name) namespaceURI:nsuri];
601 if ((node = [self->element attributeNode:_name])) {
602 node = [node retain];
603 [self->element removeAttribute:_name];
604 return [node autorelease];
612 - (id)namedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
613 return [self->element attributeNode:_name namespaceURI:_uri];
615 - (id)setNamedItemNS:(id)_node {
617 return [self->element setAttributeNodeNS:_node];
619 - (id)removeNamedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
623 if ((node = [self->element attributeNode:_name namespaceURI:_uri])) {
624 node = [node retain];
625 [self->element removeAttribute:_name namespaceURI:_uri];
626 return [node autorelease];
636 return [self->element _numberOfAttributes];
639 - (id)objectEnumerator {
644 if ((count = [self->element _numberOfAttributes]) == 0)
647 ma = [NSMutableArray arrayWithCapacity:count];
649 for (i = 0; i < count; i++)
650 [ma addObject:[self->element _attributeNodeAtIndex:i]];
652 return [ma objectEnumerator];
655 /* mimic NSDictionary */
657 - (void)setObject:(id)_value forKey:(id)_key {
659 [self takeValue:_value forKey:[_key stringValue]];
661 - (id)objectForKey:(id)_key {
663 return [self valueForKey:[_key stringValue]];
668 - (void)takeValue:(id)_value forKey:(NSString *)_key {
672 if ((node = [self->element attributeNode:_key namespaceURI:@"*"])) {
673 [node setValue:[_value stringValue]];
676 [self->element setAttribute:_key namespaceURI:@"xhtml"
677 value:[_value stringValue]];
680 - (id)valueForKey:(NSString *)_key {
684 if ((v = [self namedItem:_key]))
686 if ((v = [self namedItem:_key namespaceURI:@"*"]))
694 - (id)_jsprop_length {
695 return [NSNumber numberWithInt:[self length]];
698 - (id)_jsfunc_item:(NSArray *)_args {
701 if ((count = [_args count]) == 0) return nil;
702 return [self objectAtIndex:[[_args objectAtIndex:0] intValue]];
705 - (id)_jsfunc_getNamedItem:(NSArray *)_args {
708 if ((count = [_args count]) == 0) return nil;
709 return [self namedItem:[[_args objectAtIndex:0] stringValue]];
711 - (id)_jsfunc_getNamedItemNS:(NSArray *)_args {
714 if ((count = [_args count]) == 0) return nil;
716 return [self namedItem:[[_args objectAtIndex:0] stringValue]];
718 return [self namedItem:[[_args objectAtIndex:1] stringValue]
719 namespaceURI:[[_args objectAtIndex:0] stringValue]];
723 - (id)_jsfunc_setNamedItem:(NSArray *)_args {
727 for (i = 0, count = [_args count]; i < count; i++)
728 last = [self setNamedItem:[_args objectAtIndex:i]];
731 - (id)_jsfunc_setNamedItemNS:(NSArray *)_args {
735 for (i = 0, count = [_args count]; i < count; i++)
736 last = [self setNamedItemNS:[_args objectAtIndex:i]];
740 - (id)_jsfunc_removeNamedItem:(NSArray *)_args {
743 if ((count = [_args count]) == 0) return nil;
744 return [self namedItem:[[_args objectAtIndex:0] stringValue]];
746 - (id)_jsfunc_removeNamedItemNS:(NSArray *)_args {
749 if ((count = [_args count]) == 0) return nil;
751 return [self removeNamedItem:[[_args objectAtIndex:0] stringValue]];
753 return [self removeNamedItem:[[_args objectAtIndex:1] stringValue]
754 namespaceURI:[[_args objectAtIndex:0] stringValue]];
760 - (NSString *)description {
765 ms = [NSMutableString stringWithCapacity:1024];
766 [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
767 [ms appendFormat:@" element=%@", self->element];
769 [ms appendString:@" attributes:\n"];
770 e = [self objectEnumerator];
771 while ((attr = [e nextObject])) {
772 [ms appendString:[attr description]];
773 [ms appendString:@"\n"];
776 [ms appendString:@">"];
780 @end /* _DOMElementAttrNamedNodeMap */