2009-02-09 16:16:11 +00:00
/ * Implementation for NSXMLNode 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 .
2011-10-01 18:43:29 +00:00
2009-02-09 16:16:11 +00:00
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 09:20:32 +00:00
# define GSInternal NSXMLNodeInternal
2012-01-05 20:40:12 +00:00
# import "NSXMLPrivate.h"
# import "GSInternal.h"
2012-01-04 09:20:32 +00:00
GS_PRIVATE _INTERNAL ( NSXMLNode )
2011-10-01 18:43:29 +00:00
2011-10-17 10:24:07 +00:00
2009-02-09 16:16:11 +00:00
@ implementation NSXMLNode
+ ( id ) attributeWithName : ( NSString * ) name
stringValue : ( NSString * ) stringValue
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLAttributeKind ] autorelease ] ;
[ n setStringValue : stringValue ] ;
2011-12-30 21:40:12 +00:00
[ n setName : name ] ;
2009-02-09 16:16:11 +00:00
return n ;
}
+ ( id ) attributeWithName : ( NSString * ) name
URI : ( NSString * ) URI
stringValue : ( NSString * ) stringValue
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLAttributeKind ] autorelease ] ;
[ n setURI : URI ] ;
[ n setStringValue : stringValue ] ;
2011-12-30 21:40:12 +00:00
[ n setName : name ] ;
2009-02-09 16:16:11 +00:00
return n ;
}
+ ( id ) commentWithStringValue : ( NSString * ) stringValue
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLCommentKind ] autorelease ] ;
[ n setStringValue : stringValue ] ;
return n ;
}
+ ( id ) DTDNodeWithXMLString : ( NSString * ) string
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLDTDKind ] autorelease ] ;
[ n setStringValue : string ] ;
return n ;
}
+ ( id ) document
{
NSXMLNode * n ;
n = [ [ [ NSXMLDocument alloc ] initWithKind : NSXMLDocumentKind ] autorelease ] ;
return n ;
}
+ ( id ) documentWithRootElement : ( NSXMLElement * ) element
{
NSXMLDocument * d ;
d = [ NSXMLDocument alloc ] ;
d = [ [ d initWithRootElement : element ] autorelease ] ;
return d ;
}
+ ( id ) elementWithName : ( NSString * ) name
{
NSXMLNode * n ;
n = [ [ [ NSXMLElement alloc ] initWithName : name ] autorelease ] ;
return n ;
}
+ ( id ) elementWithName : ( NSString * ) name
children : ( NSArray * ) children
attributes : ( NSArray * ) attributes
{
NSXMLElement * e = [ self elementWithName : name ] ;
[ e insertChildren : children atIndex : 0 ] ;
[ e setAttributes : attributes ] ;
return e ;
}
+ ( id ) elementWithName : ( NSString * ) name
URI : ( NSString * ) URI
{
NSXMLNode * n ;
n = [ [ [ NSXMLElement alloc ] initWithName : name URI : URI ] autorelease ] ;
return n ;
}
+ ( id ) elementWithName : ( NSString * ) name
stringValue : ( NSString * ) string
{
NSXMLElement * e ;
NSXMLNode * t ;
2011-10-01 18:43:29 +00:00
e = [ self elementWithName : name ] ;
2009-02-09 16:16:11 +00:00
t = [ [ self alloc ] initWithKind : NSXMLTextKind ] ;
[ t setStringValue : string ] ;
[ e addChild : t ] ;
[ t release ] ;
return e ;
}
+ ( NSString * ) localNameForName : ( NSString * ) name
{
return [ self notImplemented : _cmd ] ;
}
+ ( id ) namespaceWithName : ( NSString * ) name
stringValue : ( NSString * ) stringValue
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLNamespaceKind ] autorelease ] ;
[ n setStringValue : stringValue ] ;
return n ;
}
+ ( NSXMLNode * ) predefinedNamespaceForPrefix : ( NSString * ) name
{
return [ self notImplemented : _cmd ] ;
}
+ ( NSString * ) prefixForName : ( NSString * ) name
{
return [ self notImplemented : _cmd ] ;
}
+ ( id ) processingInstructionWithName : ( NSString * ) name
stringValue : ( NSString * ) stringValue
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLProcessingInstructionKind ] autorelease ] ;
[ n setStringValue : stringValue ] ;
return n ;
}
+ ( id ) textWithStringValue : ( NSString * ) stringValue
{
NSXMLNode * n ;
n = [ [ [ self alloc ] initWithKind : NSXMLTextKind ] autorelease ] ;
[ n setStringValue : stringValue ] ;
return n ;
}
- ( NSString * ) canonicalXMLStringPreservingComments : ( BOOL ) comments
{
return [ self notImplemented : _cmd ] ; // FIXME . . . generate from libxml
}
- ( NSXMLNode * ) childAtIndex : ( NSUInteger ) index
{
2012-01-04 09:20:32 +00:00
return [ internal -> children objectAtIndex : index ] ;
2009-02-09 16:16:11 +00:00
}
- ( NSUInteger ) childCount
{
2012-01-04 09:20:32 +00:00
return internal -> childCount ;
2009-02-09 16:16:11 +00:00
}
2012-01-06 12:22:30 +00:00
- ( NSArray * ) children
2009-02-09 16:16:11 +00:00
{
2012-01-04 09:20:32 +00:00
return internal -> children ;
2009-02-09 16:16:11 +00:00
}
- ( id ) copyWithZone : ( NSZone * ) zone
{
2012-01-06 02:43:26 +00:00
id c = [ [ self class ] allocWithZone : zone ] ;
2012-01-04 12:41:45 +00:00
c = [ c initWithKind : internal -> kind options : internal -> options ] ;
[ c setName : [ self name ] ] ;
[ c setURI : [ self URI ] ] ;
[ c setObjectValue : [ self objectValue ] ] ;
[ c setStringValue : [ self stringValue ] ] ;
2012-01-06 02:43:26 +00:00
2012-01-04 12:41:45 +00:00
return c ;
2012-01-06 12:48:49 +00:00
}
2009-02-09 16:16:11 +00:00
- ( void ) dealloc
{
2012-01-04 12:41:45 +00:00
if ( GS_EXISTS _INTERNAL )
{
[ self detach ] ;
[ internal -> name release ] ;
[ internal -> URI release ] ;
[ internal -> children release ] ;
[ internal -> objectValue release ] ;
[ internal -> stringValue release ] ;
GS_DESTROY _INTERNAL ( NSXMLNode ) ;
}
2009-02-09 16:16:11 +00:00
[ super dealloc ] ;
}
- ( void ) detach
{
2012-01-07 13:08:03 +00:00
[ ( NSXMLElement * ) internal -> parent removeChildAtIndex : [ self index ] ] ;
2009-02-09 16:16:11 +00:00
}
2012-01-06 12:22:30 +00:00
- ( NSUInteger ) hash
{
return [ internal -> name hash ] ;
}
2009-02-09 16:16:11 +00:00
- ( NSUInteger ) index
{
2012-01-07 13:08:03 +00:00
if ( nil = = internal -> parent )
{
return 0 ;
}
return [ GSIVar ( internal -> parent , children ) indexOfObjectIdenticalTo : self ] ;
2009-02-09 16:16:11 +00:00
}
2011-10-01 18:43:29 +00:00
- ( id ) init
{
return [ self initWithKind : NSXMLInvalidKind ] ;
}
2009-02-09 16:16:11 +00:00
- ( id ) initWithKind : ( NSXMLNodeKind ) kind
{
self = [ self initWithKind : kind options : 0 ] ;
return self ;
}
2011-10-01 18:43:29 +00:00
- ( id ) initWithKind : ( NSXMLNodeKind ) kind options : ( NSUInteger ) theOptions
2009-02-09 16:16:11 +00:00
{
2011-10-01 18:43:29 +00:00
Class theSubclass = [ NSXMLNode class ] ;
2012-01-04 12:41:45 +00:00
2012-01-29 15:39:19 +00:00
GSOnceMLog ( @ "WARNING the XML DOM classes are not currently implemented to a usable level, but we expect to have an implementation based on libxml2 in place for the next release." ) ;
2011-10-01 18:43:29 +00:00
if ( nil = = ( self = [ super init ] ) )
2012-01-01 07:38:53 +00:00
{
return nil ;
}
2011-10-01 18:43:29 +00:00
/ *
* We find the correct subclass for specific node kinds :
* /
switch ( kind )
{
2012-01-01 07:38:53 +00:00
case NSXMLDocumentKind :
theSubclass = [ NSXMLDocument class ] ;
break ;
2012-01-04 12:41:45 +00:00
2012-01-01 07:38:53 +00:00
case NSXMLElementKind :
theSubclass = [ NSXMLElement class ] ;
break ;
2012-01-04 12:41:45 +00:00
2012-01-01 07:38:53 +00:00
case NSXMLDTDKind :
theSubclass = [ NSXMLDTD class ] ;
break ;
2012-01-04 12:41:45 +00:00
2012-01-01 07:38:53 +00:00
case NSXMLEntityDeclarationKind :
case NSXMLElementDeclarationKind :
case NSXMLNotationDeclarationKind :
theSubclass = [ NSXMLDTDNode class ] ;
break ;
2012-01-04 12:41:45 +00:00
2012-01-01 07:38:53 +00:00
default :
break ;
2011-10-01 18:43:29 +00:00
}
/ *
* Check whether we are already initializing an instance of the given
* subclass . If we are not , release ourselves and allocate a subclass instance
* instead .
* /
if ( NO = = [ self isKindOfClass : theSubclass ] )
2012-01-01 07:38:53 +00:00
{
[ self release ] ;
return [ [ theSubclass alloc ] initWithKind : kind
options : theOptions ] ;
}
2011-10-01 18:43:29 +00:00
2012-01-04 12:41:45 +00:00
/ * Create holder for internal instance variables if needed .
2011-10-01 18:43:29 +00:00
* /
2012-01-04 12:41:45 +00:00
GS_CREATE _INTERNAL ( NSXMLNode )
2011-10-01 18:43:29 +00:00
2012-01-04 12:41:45 +00:00
/ * If we are initializing for the correct class , we can actually perform
* initializations :
* /
internal -> kind = kind ;
2012-01-04 09:20:32 +00:00
internal -> options = theOptions ;
2012-01-06 12:22:30 +00:00
internal -> stringValue = @ "" ;
2009-02-09 16:16:11 +00:00
return self ;
}
2012-01-06 12:22:30 +00:00
- ( BOOL ) isEqual : ( id ) other
{
NSString * s ;
NSArray * c ;
if ( other = = ( id ) self )
{
return YES ;
}
if ( NO = = [ other isKindOfClass : [ self class ] ] )
{
return NO ;
}
if ( [ ( NSXMLNode * ) other kind ] ! = internal -> kind )
{
return NO ;
}
s = [ other name ] ;
if ( s ! = internal -> name && NO = = [ s isEqual : internal -> name ] )
{
return NO ;
}
s = [ other URI ] ;
if ( s ! = internal -> URI && NO = = [ s isEqual : internal -> URI ] )
{
return NO ;
}
c = [ other children ] ;
if ( c ! = internal -> children && NO = = [ c isEqual : internal -> children ] )
{
return NO ;
}
return YES ;
}
2009-02-09 16:16:11 +00:00
- ( NSXMLNodeKind ) kind
{
2012-01-04 12:41:45 +00:00
return internal -> kind ;
2009-02-09 16:16:11 +00:00
}
- ( NSUInteger ) level
{
NSUInteger level = 0 ;
2012-01-04 12:41:45 +00:00
NSXMLNode * tmp = internal -> parent ;
2009-02-09 16:16:11 +00:00
while ( tmp ! = nil )
{
level + + ;
2012-01-04 12:41:45 +00:00
tmp = GSIVar ( tmp , parent ) ;
2009-02-09 16:16:11 +00:00
}
return level ;
}
- ( NSString * ) localName
{
return [ self notImplemented : _cmd ] ; // FIXME . . . fetch from libxml
}
- ( NSString * ) name
{
2012-01-04 12:41:45 +00:00
return internal -> name ;
2009-02-09 16:16:11 +00:00
}
2011-10-01 18:43:29 +00:00
- ( NSXMLNode * ) _nodeFollowingInNaturalDirection : ( BOOL ) forward
{
2012-01-04 12:41:45 +00:00
NSXMLNode * ancestor = internal -> parent ;
2011-10-01 18:43:29 +00:00
NSXMLNode * candidate = nil ;
/ * Node walking is a depth - first thingy . Hence , we consider children first : * /
2012-01-04 09:20:32 +00:00
if ( 0 ! = internal -> childCount )
2011-10-01 18:43:29 +00:00
{
2012-01-01 07:38:53 +00:00
NSUInteger theIndex = 0 ;
if ( NO = = forward )
{
2012-01-04 09:20:32 +00:00
theIndex = ( internal -> childCount ) - 1 ;
2012-01-01 07:38:53 +00:00
}
2012-01-04 09:20:32 +00:00
candidate = [ internal -> children objectAtIndex : theIndex ] ;
2011-10-01 18:43:29 +00:00
}
/ * If there are no children , we move on to siblings : * /
if ( nil = = candidate )
{
2012-01-01 07:38:53 +00:00
if ( forward )
{
2012-01-04 09:20:32 +00:00
candidate = internal -> nextSibling ;
2012-01-01 07:38:53 +00:00
}
else
{
2012-01-04 09:20:32 +00:00
candidate = internal -> previousSibling ;
2012-01-01 07:38:53 +00:00
}
2011-10-01 18:43:29 +00:00
}
/ * If there are no siblings left for the receiver , we recurse down to the root
* of the tree until we find an ancestor with further siblings : * /
while ( ( nil = = candidate ) && ( nil ! = ancestor ) )
{
2012-01-01 07:38:53 +00:00
if ( forward )
{
candidate = [ ancestor nextSibling ] ;
}
else
{
candidate = [ ancestor previousSibling ] ;
}
2012-01-04 12:41:45 +00:00
ancestor = GSIVar ( ancestor , parent ) ;
2011-10-01 18:43:29 +00:00
}
/ * No children , no next siblings , no next siblings for any ancestor : We are
* the last node * /
if ( nil = = candidate )
2012-01-01 07:38:53 +00:00
{
return nil ;
}
2011-10-01 18:43:29 +00:00
/ * Sanity check : Namespace and attribute nodes are skipped : * /
2012-01-04 12:41:45 +00:00
if ( ( NSXMLAttributeKind = = GSIVar ( candidate , kind ) )
|| ( NSXMLNamespaceKind = = GSIVar ( candidate , kind ) ) )
2012-01-01 07:38:53 +00:00
{
return [ candidate _nodeFollowingInNaturalDirection : forward ] ;
}
2011-10-01 18:43:29 +00:00
return candidate ;
}
2009-02-09 16:16:11 +00:00
- ( NSXMLNode * ) nextNode
{
2011-10-01 18:43:29 +00:00
return [ self _nodeFollowingInNaturalDirection : YES ] ;
2009-02-09 16:16:11 +00:00
}
- ( NSXMLNode * ) nextSibling
{
2012-01-04 09:20:32 +00:00
return internal -> nextSibling ;
2009-02-09 16:16:11 +00:00
}
- ( id ) objectValue
{
2012-01-04 12:41:45 +00:00
return internal -> objectValue ;
2009-02-09 16:16:11 +00:00
}
- ( NSXMLNode * ) parent
{
2012-01-04 12:41:45 +00:00
return internal -> parent ;
2009-02-09 16:16:11 +00:00
}
- ( NSString * ) prefix
{
return [ self notImplemented : _cmd ] ; // FIXME . . . fetch from libxml
}
- ( NSXMLNode * ) previousNode
{
2011-10-01 18:43:29 +00:00
return [ self _nodeFollowingInNaturalDirection : NO ] ;
2009-02-09 16:16:11 +00:00
}
- ( NSXMLNode * ) previousSibling
{
2012-01-04 09:20:32 +00:00
return internal -> previousSibling ;
2011-10-01 18:43:29 +00:00
2009-02-09 16:16:11 +00:00
}
- ( NSXMLDocument * ) rootDocument
{
2012-01-04 12:41:45 +00:00
NSXMLNode * ancestor = internal -> parent ;
2011-10-01 18:43:29 +00:00
/ *
* Short - circuit evaluation gurantees that the nil - pointer is not
* dereferenced :
* /
2012-01-04 12:41:45 +00:00
while ( ( ancestor ! = nil )
&& ( NSXMLDocumentKind ! = GSIVar ( ancestor , kind ) ) )
2012-01-01 07:38:53 +00:00
{
2012-01-04 12:41:45 +00:00
ancestor = GSIVar ( ancestor , parent ) ;
2012-01-01 07:38:53 +00:00
}
2011-10-01 18:43:29 +00:00
return ( NSXMLDocument * ) ancestor ;
2009-02-09 16:16:11 +00:00
}
- ( NSString * ) stringValue
{
2012-01-04 12:41:45 +00:00
return internal -> stringValue ;
2009-02-09 16:16:11 +00:00
}
- ( NSString * ) URI
{
2012-01-04 12:41:45 +00:00
return internal -> URI ; // FIXME . . . fetch from libxml
2009-02-09 16:16:11 +00:00
}
- ( NSString * ) XMLString
{
return [ self XMLStringWithOptions : 0 ] ;
}
- ( NSString * ) XMLStringWithOptions : ( NSUInteger ) options
{
2012-01-03 17:15:29 +00:00
NSMutableString * returnValue = [ NSMutableString string ] ;
NSXMLNodeKind kind = [ self kind ] ;
2012-01-04 12:41:45 +00:00
if ( kind = = NSXMLAttributeKind )
2012-01-03 17:15:29 +00:00
{
[ returnValue appendString : [ self name ] ] ;
[ returnValue appendString : @ "=\" " ] ;
[ returnValue appendString : [ self stringValue ] ] ;
[ returnValue appendString : @ "\" " ] ;
}
else
{
// for all other types , do nothing for now . . .
}
return returnValue ;
2009-02-09 16:16:11 +00:00
}
- ( void ) setObjectValue : ( id ) value
{
2012-01-04 12:41:45 +00:00
ASSIGN ( internal -> objectValue , value ) ;
2009-02-09 16:16:11 +00:00
}
2012-01-02 07:27:56 +00:00
- ( void ) setName : ( NSString * ) name
2009-02-09 16:16:11 +00:00
{
2012-01-06 12:22:30 +00:00
if ( NSXMLInvalidKind ! = internal -> kind )
{
ASSIGNCOPY ( internal -> name , name ) ;
}
2009-02-09 16:16:11 +00:00
}
- ( void ) setStringValue : ( NSString * ) string
{
[ self setStringValue : string resolvingEntities : NO ] ;
}
- ( void ) setURI : ( NSString * ) URI
{
2012-01-06 12:22:30 +00:00
if ( NSXMLInvalidKind ! = internal -> kind )
{
ASSIGNCOPY ( internal -> URI , URI ) ;
}
2009-02-09 16:16:11 +00:00
}
- ( void ) setStringValue : ( NSString * ) string resolvingEntities : ( BOOL ) resolve
{
2012-01-04 12:41:45 +00:00
if ( resolve = = NO )
2012-01-03 17:15:29 +00:00
{
2012-01-06 12:22:30 +00:00
ASSIGNCOPY ( internal -> stringValue , string ) ;
2012-01-03 17:15:29 +00:00
}
else
{
2012-01-04 12:41:45 +00:00
// need to actually resolve entities . . .
2012-01-06 12:22:30 +00:00
ASSIGNCOPY ( internal -> stringValue , string ) ;
}
if ( nil = = internal -> stringValue )
{
internal -> stringValue = @ "" ; // string value may not be nil
2012-01-03 17:15:29 +00:00
}
2009-02-09 16:16:11 +00:00
}
- ( NSString * ) XPath
{
return [ self notImplemented : _cmd ] ;
}
- ( NSArray * ) nodesForXPath : ( NSString * ) xpath error : ( NSError * * ) error
{
return [ self notImplemented : _cmd ] ;
}
- ( NSArray * ) objectsForXQuery : ( NSString * ) xquery
constants : ( NSDictionary * ) constants
error : ( NSError * * ) error
{
return [ self notImplemented : _cmd ] ;
}
- ( NSArray * ) objectsForXQuery : ( NSString * ) xquery error : ( NSError * * ) error
{
return [ self notImplemented : _cmd ] ;
}
@ end