2009-02-09 16:16:11 +00:00
|
|
|
/* Implementation for NSXMLElement for GNUStep
|
|
|
|
Copyright (C) 2008 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
Created: September 2008
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02111 USA.
|
|
|
|
*/
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
#import "common.h"
|
|
|
|
|
2012-01-04 12:41:45 +00:00
|
|
|
#define GSInternal NSXMLElementInternal
|
2012-01-05 20:40:12 +00:00
|
|
|
#import "NSXMLPrivate.h"
|
|
|
|
#import "GSInternal.h"
|
2012-01-04 12:41:45 +00:00
|
|
|
GS_PRIVATE_INTERNAL(NSXMLElement)
|
|
|
|
|
2012-01-12 17:16:31 +00:00
|
|
|
// Private methods to manage libxml pointers...
|
|
|
|
@interface NSXMLNode (Private)
|
|
|
|
- (void *) _node;
|
|
|
|
- (void) _setNode: (void *)_anode;
|
|
|
|
@end
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
@implementation NSXMLElement
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
2012-01-04 12:41:45 +00:00
|
|
|
if (GS_EXISTS_INTERNAL && _internal != nil)
|
|
|
|
{
|
2012-01-07 13:08:03 +00:00
|
|
|
while (internal->childCount > 0)
|
|
|
|
{
|
|
|
|
[self removeChildAtIndex: internal->childCount - 1];
|
|
|
|
}
|
2012-01-04 12:41:45 +00:00
|
|
|
[internal->attributes release];
|
|
|
|
[internal->namespaces release];
|
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2012-01-05 18:55:17 +00:00
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
return [self initWithKind: NSXMLElementKind options: 0];
|
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (id) initWithName: (NSString*)name
|
|
|
|
{
|
|
|
|
return [self initWithName: name URI: nil];
|
|
|
|
}
|
|
|
|
|
2012-01-05 18:55:17 +00:00
|
|
|
- (id) initWithKind: (NSXMLNodeKind)kind options: (NSUInteger)theOptions
|
|
|
|
{
|
|
|
|
if (NSXMLElementKind == kind)
|
|
|
|
{
|
|
|
|
/* Create holder for internal instance variables so that we'll have
|
|
|
|
* all our ivars available rather than just those of the superclass.
|
|
|
|
*/
|
2012-01-12 18:50:56 +00:00
|
|
|
NSString *name = @"";
|
2012-01-05 18:55:17 +00:00
|
|
|
GS_CREATE_INTERNAL(NSXMLElement)
|
2012-01-12 18:50:56 +00:00
|
|
|
internal->node = (void *)xmlNewNode(NULL,(xmlChar *)[name UTF8String]);
|
|
|
|
internal->objectValue = @"";
|
2012-01-05 18:55:17 +00:00
|
|
|
}
|
|
|
|
return [super initWithKind: kind options: theOptions];
|
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (id) initWithName: (NSString*)name URI: (NSString*)URI
|
|
|
|
{
|
2012-01-04 12:41:45 +00:00
|
|
|
/* Create holder for internal instance variables so that we'll have
|
|
|
|
* all our ivars available rather than just those of the superclass.
|
|
|
|
*/
|
|
|
|
GS_CREATE_INTERNAL(NSXMLElement)
|
|
|
|
if ((self = [super initWithKind: NSXMLElementKind]) != nil)
|
2011-12-30 21:40:12 +00:00
|
|
|
{
|
2012-01-12 17:16:31 +00:00
|
|
|
internal->node = (void *)xmlNewNode(NULL,(xmlChar *)[name UTF8String]);
|
2012-01-06 12:22:30 +00:00
|
|
|
ASSIGNCOPY(internal->URI, URI);
|
|
|
|
internal->objectValue = @"";
|
2011-12-30 21:40:12 +00:00
|
|
|
}
|
|
|
|
return self;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name stringValue: (NSString*)string
|
|
|
|
{
|
2012-01-04 12:41:45 +00:00
|
|
|
if ([self initWithName: name URI: nil] != nil)
|
2012-01-03 03:28:25 +00:00
|
|
|
{
|
|
|
|
[self setObjectValue: string];
|
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithXMLString: (NSString*)string error: (NSError**)error
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) elementsForName: (NSString*)name
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) elementsForLocalName: (NSString*)localName URI: (NSString*)URI
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addAttribute: (NSXMLNode*)attribute
|
|
|
|
{
|
2012-01-12 17:16:31 +00:00
|
|
|
xmlNodePtr node = (xmlNodePtr)(internal->node);
|
|
|
|
xmlNodePtr attr = (xmlNodePtr)[attribute _node];
|
|
|
|
xmlAddChild(node,attr);
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeAttributeForName: (NSString*)name
|
|
|
|
{
|
2012-01-12 17:16:31 +00:00
|
|
|
xmlNodePtr node = (xmlNodePtr)(internal->node);
|
|
|
|
xmlUnsetProp(node,(xmlChar *)[name UTF8String]);
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setAttributes: (NSArray*)attributes
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [attributes objectEnumerator];
|
|
|
|
NSXMLNode *attribute;
|
|
|
|
|
|
|
|
while ((attribute = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[self addAttribute: attribute];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setAttributesAsDictionary: (NSDictionary*)attributes
|
2012-01-06 12:22:30 +00:00
|
|
|
{
|
|
|
|
[self setAttributesWithDictionary: attributes];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setAttributesWithDictionary: (NSDictionary*)attributes
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
2012-01-05 15:44:45 +00:00
|
|
|
NSEnumerator *en = [attributes keyEnumerator];
|
|
|
|
NSString *key;
|
|
|
|
|
2012-01-06 12:22:30 +00:00
|
|
|
[internal->attributes removeAllObjects];
|
2012-01-05 15:44:45 +00:00
|
|
|
while ((key = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *val = [attributes objectForKey: key];
|
|
|
|
NSXMLNode *attribute = [NSXMLNode attributeWithName: key
|
|
|
|
stringValue: val];
|
|
|
|
[self addAttribute: attribute];
|
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) attributes
|
|
|
|
{
|
2012-01-04 12:41:45 +00:00
|
|
|
return [internal->attributes allValues];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) attributeForName: (NSString*)name
|
|
|
|
{
|
2012-01-04 12:41:45 +00:00
|
|
|
return [internal->attributes objectForKey: name];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) attributeForLocalName: (NSString*)localName
|
2012-01-06 12:22:30 +00:00
|
|
|
URI: (NSString*)URI
|
2009-02-09 16:16:11 +00:00
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addNamespace: (NSXMLNode*)aNamespace
|
|
|
|
{
|
2012-01-12 17:16:31 +00:00
|
|
|
[self notImplemented: _cmd];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeNamespaceForPrefix: (NSString*)name
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setNamespaces: (NSArray*)namespaces
|
|
|
|
{
|
2012-01-12 17:16:31 +00:00
|
|
|
[self notImplemented: _cmd];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
2012-01-06 12:22:30 +00:00
|
|
|
- (void) setObjectValue: (id)value
|
|
|
|
{
|
|
|
|
if (nil == value)
|
|
|
|
{
|
|
|
|
value = @""; // May not be nil
|
|
|
|
}
|
|
|
|
ASSIGN(internal->objectValue, value);
|
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (NSArray*) namespaces
|
|
|
|
{
|
2012-01-04 12:41:45 +00:00
|
|
|
return internal->namespaces;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) namespaceForPrefix: (NSString*)name
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSXMLNode*) resolveNamespaceForName: (NSString*)name
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) resolvePrefixForNamespaceURI: (NSString*)namespaceURI
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) insertChild: (NSXMLNode*)child atIndex: (NSUInteger)index
|
|
|
|
{
|
2012-01-06 12:22:30 +00:00
|
|
|
NSXMLNodeKind kind;
|
2012-01-12 23:19:26 +00:00
|
|
|
xmlNodePtr node = (xmlNodePtr)(internal->node);
|
2012-01-06 12:22:30 +00:00
|
|
|
|
|
|
|
NSAssert(nil != child, NSInvalidArgumentException);
|
|
|
|
NSAssert(index <= internal->childCount, NSInvalidArgumentException);
|
2012-01-07 13:08:03 +00:00
|
|
|
NSAssert(nil == [child parent], NSInternalInconsistencyException);
|
|
|
|
kind = [child kind];
|
2012-01-06 23:00:03 +00:00
|
|
|
// FIXME ... should we check for valid kinds rather than invalid ones?
|
2012-01-06 12:22:30 +00:00
|
|
|
NSAssert(NSXMLAttributeKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLDTDKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLDocumentKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLElementDeclarationKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLEntityDeclarationKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLInvalidKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLNamespaceKind != kind, NSInvalidArgumentException);
|
|
|
|
NSAssert(NSXMLNotationDeclarationKind != kind, NSInvalidArgumentException);
|
|
|
|
|
|
|
|
if (nil == internal->children)
|
|
|
|
{
|
|
|
|
internal->children = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
|
|
}
|
2012-01-06 02:43:26 +00:00
|
|
|
[internal->children insertObject: child
|
|
|
|
atIndex: index];
|
2012-01-06 12:22:30 +00:00
|
|
|
GSIVar(child, parent) = self;
|
2012-01-06 03:11:14 +00:00
|
|
|
internal->childCount++;
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) insertChildren: (NSArray*)children atIndex: (NSUInteger)index
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator = [children objectEnumerator];
|
|
|
|
NSXMLNode *child;
|
2011-12-30 21:40:12 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
while ((child = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[self insertChild: child atIndex: index++];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeChildAtIndex: (NSUInteger)index
|
|
|
|
{
|
2012-01-07 13:08:03 +00:00
|
|
|
NSXMLNode *child;
|
2012-01-13 19:44:55 +00:00
|
|
|
xmlNodePtr n;
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2012-01-13 19:44:55 +00:00
|
|
|
if (index >= [self childCount])
|
2012-01-06 12:22:30 +00:00
|
|
|
{
|
2012-01-07 13:08:03 +00:00
|
|
|
[NSException raise: NSRangeException
|
|
|
|
format: @"index to large"];
|
|
|
|
}
|
2012-01-13 19:44:55 +00:00
|
|
|
|
|
|
|
child = [[self children] objectAtIndex: index];
|
|
|
|
n = [child _node];
|
|
|
|
xmlUnlinkNode(n);
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setChildren: (NSArray*)children
|
|
|
|
{
|
2012-01-06 12:22:30 +00:00
|
|
|
if (children != internal->children)
|
2012-01-06 02:43:26 +00:00
|
|
|
{
|
2012-01-06 12:22:30 +00:00
|
|
|
NSEnumerator *en;
|
|
|
|
NSXMLNode *child;
|
|
|
|
|
|
|
|
[children retain];
|
|
|
|
while (internal->childCount > 0)
|
|
|
|
{
|
|
|
|
[self removeChildAtIndex:internal->childCount - 1];
|
|
|
|
}
|
|
|
|
en = [children objectEnumerator];
|
|
|
|
while ((child = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[self insertChild: child atIndex: internal->childCount];
|
|
|
|
}
|
|
|
|
[children release];
|
2012-01-06 02:43:26 +00:00
|
|
|
}
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
2011-12-30 21:40:12 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (void) addChild: (NSXMLNode*)child
|
|
|
|
{
|
2012-01-13 19:44:55 +00:00
|
|
|
int count = [self childCount];
|
|
|
|
[self insertChild: child atIndex: count];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
2011-12-30 21:40:12 +00:00
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
- (void) replaceChildAtIndex: (NSUInteger)index withNode: (NSXMLNode*)node
|
|
|
|
{
|
2011-12-30 21:40:12 +00:00
|
|
|
[self insertChild: node atIndex: index];
|
2012-01-06 12:22:30 +00:00
|
|
|
[self removeChildAtIndex: index + 1];
|
2009-02-09 16:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) normalizeAdjacentTextNodesPreservingCDATA: (BOOL)preserve
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
}
|
|
|
|
|
2012-01-06 02:43:26 +00:00
|
|
|
- (id) copyWithZone: (NSZone *)zone
|
|
|
|
{
|
2012-01-06 12:22:30 +00:00
|
|
|
NSXMLElement *c = (NSXMLElement*)[super copyWithZone: zone];
|
2012-01-07 13:08:03 +00:00
|
|
|
NSEnumerator *en;
|
|
|
|
id obj;
|
2012-01-06 02:43:26 +00:00
|
|
|
|
2012-01-07 13:08:03 +00:00
|
|
|
en = [internal->namespaces objectEnumerator];
|
2012-01-06 12:22:30 +00:00
|
|
|
while ((obj = [en nextObject]) != nil)
|
2012-01-06 02:43:26 +00:00
|
|
|
{
|
2012-01-07 13:08:03 +00:00
|
|
|
NSXMLNode *ns = [obj copyWithZone: zone];
|
|
|
|
|
|
|
|
[c addNamespace: ns];
|
|
|
|
[ns release];
|
2012-01-06 02:43:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
en = [internal->attributes objectEnumerator];
|
2012-01-06 12:22:30 +00:00
|
|
|
while ((obj = [en nextObject]) != nil)
|
2012-01-06 02:43:26 +00:00
|
|
|
{
|
|
|
|
NSXMLNode *attr = [obj copyWithZone: zone];
|
2012-01-07 13:08:03 +00:00
|
|
|
|
2012-01-06 02:43:26 +00:00
|
|
|
[c addAttribute: attr];
|
2012-01-07 13:08:03 +00:00
|
|
|
[attr release];
|
2012-01-06 02:43:26 +00:00
|
|
|
}
|
|
|
|
|
2012-01-07 13:08:03 +00:00
|
|
|
en = [internal->children objectEnumerator];
|
|
|
|
while ((obj = [en nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSXMLNode *child = [obj copyWithZone: zone];
|
|
|
|
|
|
|
|
[c addChild: child];
|
|
|
|
[child release];
|
|
|
|
}
|
2012-01-06 12:22:30 +00:00
|
|
|
|
2012-01-06 03:09:14 +00:00
|
|
|
return c;
|
2012-01-06 02:43:26 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 16:16:11 +00:00
|
|
|
@end
|
|
|
|
|