2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <DOM/DOMElement.h>
23 #include <DOM/DOMNamedNodeMap.h>
24 #include <DOM/DOMAttribute.h>
25 #include <DOM/DOMDocument.h>
26 #include <DOM/DOMNodeWalker.h>
29 @interface _DOMElementAttrNamedNodeMap : NSObject < DOMNamedNodeMap >
31 NGDOMElement *element; /* non-retained */
34 - (id)initWithElement:(id)_element;
36 - (id)objectEnumerator;
40 @end /* _DOMElementAttrNamedNodeMap */
42 @interface NGDOMElement(Privates)
43 - (unsigned)_numberOfAttributes;
44 - (id)_attributeNodeAtIndex:(unsigned)_idx;
45 - (id)attributeNode:(NSString *)_localName;
46 - (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns;
49 static NSNull *null = nil;
51 @implementation NGDOMElement
53 - (id)initWithTagName:(NSString *)_tagName namespaceURI:(NSString *)_uri {
55 null = [[NSNull null] retain];
57 if ((self = [super init])) {
58 self->tagName = [_tagName copy];
59 self->namespaceURI = [_uri copy];
63 - (id)initWithTagName:(NSString *)_tagName {
64 return [self initWithTagName:_tagName namespaceURI:nil];
68 [self->attributes makeObjectsPerformSelector:
69 @selector(_domNodeForgetParentNode:)
72 [self->attrNodeMap invalidate];
73 [self->attrNodeMap release];
74 [self->keyToAttribute release];
75 [self->attributes release];
76 [self->tagName release];
77 [self->namespaceURI release];
78 [self->prefix release];
84 - (NSString *)tagName {
88 - (void)setPrefix:(NSString *)_prefix {
89 id old = self->prefix;
90 self->prefix = [_prefix copy];
93 - (NSString *)prefix {
97 - (NSString *)namespaceURI {
98 return self->namespaceURI;
101 - (void)setLine:(unsigned)_line {
110 - (void)_walk_getElementsByTagName:(id)_walker {
113 node = [_walker currentNode];
114 if ([node nodeType] != DOM_ELEMENT_NODE)
117 if (![[node tagName] isEqualToString:
118 [(NSArray *)[_walker context] objectAtIndex:0]])
119 /* tagname doesn't match */
122 [[(NSArray *)[_walker context] objectAtIndex:1] addObject:node];
124 - (void)_walk_getElementsByTagNameAddAll:(id)_walker {
127 node = [_walker currentNode];
128 if ([node nodeType] != DOM_ELEMENT_NODE)
131 [(NSMutableArray *)[_walker context] addObject:node];
133 - (id<NSObject,DOMNodeList>)getElementsByTagName:(NSString *)_tagName {
134 /* introduced in DOM2, should return a *live* list ! */
135 NGDOMNodePreorderWalker *walker;
136 NSMutableArray *array;
140 if (![self hasChildNodes])
146 array = [NSMutableArray arrayWithCapacity:4];
148 if ([_tagName isEqualToString:@"*"]) {
151 sel = @selector(_walk_getElementsByTagNameAddAll:);
154 ctx = [NSArray arrayWithObjects:_tagName, array, nil];
155 sel = @selector(_walk_getElementsByTagName:);
158 walker = [[NGDOMNodePreorderWalker alloc]
159 initWithTarget:self selector:sel context:ctx];
161 [walker walkNode:self];
163 [walker release]; walker = nil;
164 return [[array copy] autorelease];
166 - (id<NSObject,DOMNodeList>)getElementsByTagName:(NSString *)_tagName
167 namespaceURI:(NSString *)_uri
170 [self doesNotRecognizeSelector:_cmd];
174 /* element attributes */
176 - (void)_ensureAttrs {
177 if (self->attributes == nil)
178 self->attributes = [[NSMutableArray alloc] init];
179 if (self->keyToAttribute == nil)
180 self->keyToAttribute = [[NSMutableDictionary alloc] init];
183 - (void)_attributeSetChanged {
186 - (unsigned)_numberOfAttributes {
187 return [self->attributes count];
189 - (id)_attributeNodeAtIndex:(unsigned)_idx {
190 if (_idx >= [self->attributes count])
192 return [self->attributes objectAtIndex:_idx];
195 - (id)_keyForAttribute:(id<DOMAttr>)_attrNode {
196 return [_attrNode name];
198 - (id)_nskeyForLocalName:(NSString *)attrName namespaceURI:(NSString *)nsURI {
209 key = [NSArray arrayWithObjects:objs count:2];
216 - (id)_nskeyForAttribute:(id<DOMAttr>)_attrNode {
219 if ((attrName = [_attrNode name]) == nil) {
220 NSLog(@"WARNING: attribute %@ has no valid attribute name !", _attrNode);
224 return [self _nskeyForLocalName:attrName
225 namespaceURI:[_attrNode namespaceURI]];
228 - (BOOL)hasAttribute:(NSString *)_attrName {
229 return [self hasAttribute:_attrName namespaceURI:[self namespaceURI]];
232 - (void)setAttribute:(NSString *)_attrName value:(NSString *)_value {
233 [self setAttribute:_attrName namespaceURI:[self namespaceURI] value:_value];
238 NSAssert1(_attrName, @"invalid attribute name '%@'", _attrName);
240 if ((node = [self->keyToAttribute objectForKey:_attrName]) == nil) {
241 /* create new node */
242 node = [[self ownerDocument] createAttribute:_attrName];
244 NSAssert(node, @"couldn't find/create node for attribute");
246 node = [self setAttributeNode:node];
248 [node setValue:_value];
251 - (id)attributeNode:(NSString *)_attrName {
252 return [self attributeNode:_attrName namespaceURI:[self namespaceURI]];
254 - (NSString *)attribute:(NSString *)_attrName {
255 return [[self attributeNode:_attrName] value];
258 - (BOOL)hasAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
262 if ([_ns isEqualToString:@"*"]) {
263 /* match any namespace */
267 if ((attr = [self->keyToAttribute objectForKey:_localName]))
270 e = [self->keyToAttribute keyEnumerator];
271 while ((key = [e nextObject])) {
272 if ([key isKindOfClass:[NSArray class]]) {
273 if ([[key objectAtIndex:0] isEqualToString:_localName])
280 objs[0] = _localName;
281 objs[1] = _ns ? _ns : (id)null;
282 key = [NSArray arrayWithObjects:objs count:2];
284 return [self->keyToAttribute objectForKey:key] ? YES : NO;
287 - (void)setAttribute:(NSString *)_localName namespaceURI:(NSString *)_ns
288 value:(NSString *)_value
293 key = [self _nskeyForLocalName:_localName namespaceURI:_ns];
294 NSAssert2(key, @"invalid (ns-)attribute name localName='%@', uri='%@'",
297 if ((node = [self->keyToAttribute objectForKey:key]) == nil) {
298 /* create new node */
299 node = [[self ownerDocument] createAttribute:_localName namespaceURI:_ns];
301 NSAssert(node, @"couldn't find/create node for attribute");
303 node = [self setAttributeNodeNS:node];
305 [node setValue:_value];
307 - (id)attributeNode:(NSString *)_localName namespaceURI:(NSString *)_ns {
311 if ([_ns isEqualToString:@"*"]) {
312 /* match any namespace */
316 if ((attr = [self->keyToAttribute objectForKey:_localName]))
319 e = [self->keyToAttribute keyEnumerator];
320 while ((key = [e nextObject])) {
321 if ([key isKindOfClass:[NSArray class]]) {
322 if ([[key objectAtIndex:0] isEqualToString:_localName])
323 return [self->keyToAttribute objectForKey:key];
329 objs[0] = _localName;
330 objs[1] = _ns ? _ns : (id)null;
331 key = [NSArray arrayWithObjects:objs count:2];
333 return [self->keyToAttribute objectForKey:key];
335 - (NSString *)attribute:(NSString *)_localName namespaceURI:(NSString *)_ns {
336 return [[self attributeNode:_localName namespaceURI:_ns] value];
339 - (id<NSObject, DOMAttr>)setAttributeNodeNS:(id<NSObject, DOMAttr>)_attrNode {
342 if (_attrNode == nil)
343 /* invalid node parameters */
346 if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
347 /* couldn't get key */
352 /* check if the key is already added */
354 if ((oldNode = [self->keyToAttribute objectForKey:key])) {
355 if (oldNode == _attrNode) {
356 /* already contained */
357 // NSLog(@"node is already set !");
361 /* replace existing node */
362 [self->attributes replaceObjectAtIndex:
363 [self->attributes indexOfObject:oldNode]
364 withObject:_attrNode];
365 [self->keyToAttribute setObject:_attrNode forKey:key];
367 [(id)_attrNode _domNodeRegisterParentNode:self];
368 [self _attributeSetChanged];
375 NSAssert(self->keyToAttribute, @"missing keyToAttribute");
376 NSAssert(self->attributes, @"missing attrs");
378 [self->keyToAttribute setObject:_attrNode forKey:key];
379 [self->attributes addObject:_attrNode];
381 [(id)_attrNode _domNodeRegisterParentNode:self];
382 [self _attributeSetChanged];
384 // NSLog(@"added attr %@, elem %@", _attrNode, self);
390 - (void)removeAttribute:(NSString *)_attr namespaceURI:(NSString *)_uri {
394 key = [self _nskeyForLocalName:_attr namespaceURI:_uri];
395 NSAssert2(key, @"invalid (ns-)attribute name '%@', '%@'", _attr, _uri);
397 node = [self->keyToAttribute objectForKey:key];
399 [self removeAttributeNodeNS:node];
401 - (id<NSObject,DOMAttr>)removeAttributeNodeNS:(id<NSObject,DOMAttr>)_attrNode {
404 if (_attrNode == nil)
405 /* invalid node parameters */
408 if (self->attributes == nil)
409 /* no attributes are set up */
412 if ((key = [self _nskeyForAttribute:_attrNode]) == nil)
413 /* couldn't get key for node */
416 if ((oldNode = [self->keyToAttribute objectForKey:key])) {
417 /* the node's key exists */
418 if (oldNode != _attrNode) {
419 /* the node has the same key, but isn't the same */
423 /* ok, found the node, let's remove ! */
424 [[_attrNode retain] autorelease];
425 [self->keyToAttribute removeObjectForKey:key];
426 [self->attributes removeObjectIdenticalTo:_attrNode];
428 [(id)_attrNode _domNodeForgetParentNode:self];
429 [self _attributeSetChanged];
434 /* no such attribute is stored */
438 - (id<NSObject,DOMAttr>)setAttributeNode:(id<NSObject,DOMAttr>)_attrNode {
439 [self doesNotRecognizeSelector:_cmd];
442 - (id<NSObject,DOMAttr>)removeAttributeNode:(id<NSObject,DOMAttr>)_attrNode {
443 [self doesNotRecognizeSelector:_cmd];
446 - (void)removeAttribute:(NSString *)_attr {
449 NSAssert1(_attr, @"invalid attribute name '%@'", _attr);
451 node = [self->keyToAttribute objectForKey:_attr];
453 [self removeAttributeNode:node];
458 - (BOOL)_isValidChildNode:(id)_node {
459 switch ([_node nodeType]) {
460 case DOM_ELEMENT_NODE:
462 case DOM_COMMENT_NODE:
463 case DOM_PROCESSING_INSTRUCTION_NODE:
464 case DOM_CDATA_SECTION_NODE:
465 case DOM_ENTITY_REFERENCE_NODE:
473 - (DOMNodeType)nodeType {
474 return DOM_ELEMENT_NODE;
477 - (id<NSObject,DOMNamedNodeMap>)attributes {
478 /* returns a named-node-map */
479 if (self->attrNodeMap == nil) {
481 [[_DOMElementAttrNamedNodeMap alloc] initWithElement:self];
483 return self->attrNodeMap;
488 - (void)_domNodeRegisterParentNode:(id)_parent {
489 self->parent = _parent;
491 - (void)_domNodeForgetParentNode:(id)_parent {
492 if (_parent == self->parent)
493 /* the node's parent was deallocated */
496 - (id<NSObject,DOMNode>)parentNode {
502 - (NSString *)description {
503 return [NSString stringWithFormat:
504 @"<0x%08X[%@]: name=%@ parent=%@ #attrs=%i #children=%i>",
505 self, NSStringFromClass([self class]),
507 [[self parentNode] nodeName],
508 [self _numberOfAttributes],
509 [self hasChildNodes] ? [[self childNodes] length] : 0];
514 - (NSException *)setQueryPathValue:(id)_value {
515 return [NSException exceptionWithName:@"QueryPathEvalException"
516 reason:@"cannot set query-path value on DOMElement !"
519 - (id)queryPathValue {
520 return [self childNodes];
523 @end /* NGDOMElement */
525 @implementation _DOMElementAttrNamedNodeMap
527 - (id)initWithElement:(id)_element {
528 self->element = _element;
536 static inline void _checkValid(_DOMElementAttrNamedNodeMap *self) {
537 if (self->element == nil) {
538 NSCAssert(self->element,
539 @"named node map is invalid (element was deallocated) !");
545 static NSString *_XNSUri(NSString *_name) {
548 if (![_name hasPrefix:@"{"])
551 r1 = [_name rangeOfString:@"}"];
555 r1.length = (r1.location - 2);
557 return [_name substringWithRange:r1];
559 static NSString *_XNSLocalName(NSString *_name) {
562 r = [_name rangeOfString:@"}"];
565 : [_name substringFromIndex:(r.location + r.length)];
570 return [self->element _numberOfAttributes];
572 - (id)objectAtIndex:(unsigned)_idx {
574 return [self->element _attributeNodeAtIndex:_idx];
577 - (IDOMNode)namedItem:(NSString *)_name {
581 if ((nsuri = _XNSUri(_name)))
582 return [self namedItem:_XNSLocalName(_name) namespaceURI:nsuri];
584 return [self->element attributeNode:_name];
586 - (IDOMNode)setNamedItem:(IDOMNode)_node {
589 // TODO: is the cast correct?
590 return [self->element setAttributeNode:(id<NSObject,DOMAttr>)_node];
592 - (IDOMNode)removeNamedItem:(NSString *)_name {
597 if ((nsuri = _XNSUri(_name)))
598 return [self removeNamedItem:_XNSLocalName(_name) namespaceURI:nsuri];
600 if ((node = [self->element attributeNode:_name])) {
601 node = [node retain];
602 [self->element removeAttribute:_name];
603 return [node autorelease];
611 - (IDOMNode)namedItem:(NSString *)_name namespaceURI:(NSString *)_uri {
612 return [self->element attributeNode:_name namespaceURI:_uri];
614 - (IDOMNode)setNamedItemNS:(IDOMNode)_node {
616 // TODO: is the cast correct?
617 return [self->element setAttributeNodeNS:(id<NSObject,DOMAttr>)_node];
619 - (IDOMNode)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 */