384 lines
8.0 KiB
Objective-C
384 lines
8.0 KiB
Objective-C
#import "XMLTree.h"
|
|
|
|
@interface XMLTree (PrivateAPI)
|
|
|
|
|
|
@end // End Private API
|
|
|
|
|
|
|
|
@implementation XMLTree
|
|
|
|
|
|
-(void)dealloc
|
|
{
|
|
//NSLog( @"dealloc %@", self );
|
|
|
|
if( _tree != NULL )
|
|
CFRelease( _tree );
|
|
|
|
if( _node != NULL )
|
|
CFRelease( _node );
|
|
|
|
_tree = NULL;
|
|
_node = NULL;
|
|
|
|
} // end dealloc
|
|
|
|
|
|
|
|
+(XMLTree *)treeWithURL:(NSURL *)url
|
|
{
|
|
return [[[XMLTree alloc] initWithURL:url] autorelease];
|
|
} // end treeWithURL
|
|
|
|
|
|
|
|
-(XMLTree *)init
|
|
{
|
|
if( [super init] == nil )
|
|
return nil;
|
|
|
|
_tree = NULL;
|
|
_node = NULL;
|
|
|
|
return self;
|
|
} // end init
|
|
|
|
|
|
|
|
-(XMLTree *)initWithCFXMLTreeRef:(CFXMLTreeRef)ref
|
|
{
|
|
if( [self init] == nil )
|
|
return nil;
|
|
|
|
// Clean up?
|
|
if( _tree != NULL )
|
|
CFRelease( _tree );
|
|
if( _node != NULL )
|
|
CFRelease( _node );
|
|
|
|
_tree = ref;
|
|
_node = CFXMLTreeGetNode( _tree );
|
|
|
|
CFRetain( _tree );
|
|
CFRetain( _node );
|
|
|
|
return self;
|
|
} // end initWithCFXMLTreeRef:
|
|
|
|
|
|
-(XMLTree *)initWithURL:(NSURL *)url
|
|
{
|
|
CFDataRef xmlData;
|
|
if( (xmlData = (CFDataRef)malloc( sizeof( CFDataRef ) ) ) == NULL){
|
|
NSLog(@"Couldn't allocate any memory.");
|
|
return nil;
|
|
} // end if: malloc fail
|
|
|
|
|
|
_tree = CFXMLTreeCreateWithDataFromURL(
|
|
kCFAllocatorDefault,
|
|
(CFURLRef)url,
|
|
kCFXMLParserSkipWhitespace,
|
|
NULL ); //CFIndex
|
|
|
|
_node = CFXMLTreeGetNode( _tree );
|
|
|
|
// _tree is implicitly retained
|
|
CFRetain( _node );
|
|
|
|
return self;
|
|
} // end initWithURL
|
|
|
|
|
|
|
|
|
|
|
|
/* ******** A B O U T C H I L D R E N ******** */
|
|
|
|
|
|
-(int)count
|
|
{
|
|
if( _tree == NULL )
|
|
return -1;
|
|
|
|
return CFTreeGetChildCount( _tree );
|
|
} // end count
|
|
|
|
|
|
|
|
-(XMLTree *)childAtIndex:(int)index
|
|
{
|
|
CFXMLTreeRef child;
|
|
|
|
if( _tree == NULL )
|
|
return nil;
|
|
|
|
if( index >= CFTreeGetChildCount( _tree ) )
|
|
return nil;
|
|
|
|
child = CFTreeGetChildAtIndex(_tree, index);
|
|
|
|
return [[XMLTree alloc] initWithCFXMLTreeRef:child];
|
|
} // end childAtIndex:
|
|
|
|
|
|
|
|
-(XMLTree *)childNamed:(NSString *)name
|
|
{
|
|
CFXMLTreeRef childTree;
|
|
CFXMLNodeRef childNode;
|
|
CFStringRef childName;
|
|
int childCount;
|
|
int i;
|
|
|
|
if( _tree == NULL )
|
|
return nil;
|
|
|
|
childCount = CFTreeGetChildCount( _tree );
|
|
|
|
for( i = 0; i < childCount; i++ ){
|
|
childTree = CFTreeGetChildAtIndex(_tree, i );
|
|
childNode = CFXMLTreeGetNode( childTree );
|
|
childName = CFXMLNodeGetString( childNode );
|
|
|
|
if( CFStringCompare( (CFStringRef)name, childName, NULL ) == kCFCompareEqualTo )
|
|
return [[XMLTree alloc] initWithCFXMLTreeRef:childTree];
|
|
|
|
} // end for: each child
|
|
|
|
return nil;
|
|
} // end childNamed:
|
|
|
|
|
|
-(XMLTree *)descendentNamed:(NSString *)name
|
|
{
|
|
CFXMLTreeRef descTree;
|
|
|
|
if( _tree == NULL )
|
|
return nil;
|
|
|
|
descTree = XMLTreeDescendentNamed( (CFStringRef)name, _tree );
|
|
|
|
if( descTree == NULL )
|
|
return nil;
|
|
|
|
return [[XMLTree alloc] initWithCFXMLTreeRef:descTree];
|
|
} // end descendentNamed:
|
|
|
|
|
|
|
|
/* ******** A B O U T S E L F ******** */
|
|
|
|
|
|
|
|
|
|
-(NSString *)name
|
|
{
|
|
NSString *name;
|
|
|
|
if( _node == NULL )
|
|
return nil;
|
|
|
|
name = [[NSString alloc] initWithString:(NSString *)CFXMLNodeGetString(_node)];
|
|
|
|
return name;
|
|
} // end name
|
|
|
|
|
|
/*!
|
|
@discussion
|
|
Returns the node type, as defined by Apple's XML parser.
|
|
The values will be one of the following constants:
|
|
<pre>
|
|
enum CFXMLNodeTypeCode {
|
|
kCFXMLNodeTypeDocument = 1,
|
|
kCFXMLNodeTypeElement = 2,
|
|
kCFXMLNodeTypeAttribute = 3,
|
|
kCFXMLNodeTypeProcessingInstruction = 4,
|
|
kCFXMLNodeTypeComment = 5,
|
|
kCFXMLNodeTypeText = 6,
|
|
kCFXMLNodeTypeCDATASection = 7,
|
|
kCFXMLNodeTypeDocumentFragment = 8,
|
|
kCFXMLNodeTypeEntity = 9,
|
|
kCFXMLNodeTypeEntityReference = 10,
|
|
kCFXMLNodeTypeDocumentType = 11,
|
|
kCFXMLNodeTypeWhitespace = 12,
|
|
kCFXMLNodeTypeNotation = 13,
|
|
kCFXMLNodeTypeElementTypeDeclaration = 14,
|
|
kCFXMLNodeTypeAttributeListDeclaration = 15
|
|
};
|
|
</pre>
|
|
*/
|
|
-(CFXMLNodeTypeCode)type
|
|
{
|
|
return CFXMLNodeGetTypeCode(_node);
|
|
} // end type
|
|
|
|
|
|
|
|
-(NSDictionary *)attributes
|
|
{
|
|
CFXMLElementInfo eInfo;
|
|
|
|
if( CFXMLNodeGetTypeCode( _node ) != kCFXMLNodeTypeElement )
|
|
return nil;
|
|
|
|
eInfo = *(CFXMLElementInfo *)CFXMLNodeGetInfoPtr(_node);
|
|
|
|
return (NSDictionary *)eInfo.attributes;
|
|
} // end attributes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-(NSString *)attributeNamed:(NSString *)name
|
|
{
|
|
if( _tree == NULL )
|
|
return nil;
|
|
|
|
return [[[self attributes] objectForKey:name] description];
|
|
} // end attributeNamed:
|
|
|
|
|
|
|
|
|
|
|
|
-(NSString *)description
|
|
{
|
|
NSMutableString *descr;
|
|
|
|
descr = [[NSMutableString alloc] init];
|
|
|
|
//NSLog( @"Description for type %d", CFXMLNodeGetTypeCode(_node) );
|
|
|
|
switch( CFXMLNodeGetTypeCode(_node) ){
|
|
|
|
case kCFXMLNodeTypeDocument:
|
|
case kCFXMLNodeTypeElement:
|
|
XMLTreeDescription( (CFMutableStringRef)descr, _tree );
|
|
break;
|
|
|
|
case kCFXMLNodeTypeProcessingInstruction:
|
|
case kCFXMLNodeTypeAttribute:
|
|
case kCFXMLNodeTypeComment:
|
|
case kCFXMLNodeTypeText:
|
|
case kCFXMLNodeTypeCDATASection:
|
|
case kCFXMLNodeTypeDocumentFragment:
|
|
case kCFXMLNodeTypeEntity:
|
|
case kCFXMLNodeTypeEntityReference:
|
|
case kCFXMLNodeTypeDocumentType:
|
|
case kCFXMLNodeTypeWhitespace:
|
|
case kCFXMLNodeTypeNotation:
|
|
case kCFXMLNodeTypeElementTypeDeclaration:
|
|
case kCFXMLNodeTypeAttributeListDeclaration:
|
|
default:
|
|
[descr appendString:(NSString *)CFXMLNodeGetString(_node)];
|
|
} // end switch
|
|
|
|
return descr;
|
|
} // end description
|
|
|
|
|
|
|
|
|
|
-(NSString *)xml
|
|
{
|
|
CFDataRef xmlData;
|
|
|
|
if( _tree == NULL )
|
|
return nil;
|
|
|
|
xmlData = CFXMLTreeCreateXMLData(
|
|
kCFAllocatorDefault,
|
|
_tree );
|
|
if( xmlData == NULL )
|
|
return nil;
|
|
|
|
return [[NSString alloc] initWithData:(NSData *)xmlData encoding:NSASCIIStringEncoding];
|
|
|
|
} // end xml
|
|
|
|
|
|
|
|
|
|
@end // End implementation
|
|
|
|
|
|
|
|
CFStringRef XMLTreeDescription( CFMutableStringRef descr, CFXMLTreeRef tree )
|
|
{
|
|
CFXMLTreeRef childTree;
|
|
CFXMLNodeRef childNode;
|
|
int childCount;
|
|
int i;
|
|
|
|
childCount = CFTreeGetChildCount( tree );
|
|
|
|
for( i = 0; i < childCount; i++ ){
|
|
|
|
childTree = CFTreeGetChildAtIndex( tree, i );
|
|
childNode = CFXMLTreeGetNode( childTree );
|
|
|
|
switch( CFXMLNodeGetTypeCode( childNode ) ){
|
|
|
|
case kCFXMLNodeTypeText:
|
|
CFStringAppend( descr, CFXMLNodeGetString( childNode ) );
|
|
break;
|
|
|
|
case kCFXMLNodeTypeElement:
|
|
XMLTreeDescription( descr, childTree );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} // end switch: node type
|
|
} // end for
|
|
|
|
return descr;
|
|
} // end XMLTreeDescription
|
|
|
|
|
|
|
|
CFXMLTreeRef XMLTreeDescendentNamed( CFStringRef name, CFXMLTreeRef tree )
|
|
{
|
|
CFXMLTreeRef childTree;
|
|
CFXMLTreeRef descTree;
|
|
CFXMLNodeRef childNode;
|
|
CFStringRef childName;
|
|
int childCount;
|
|
int i;
|
|
|
|
childCount = CFTreeGetChildCount( tree );
|
|
|
|
for( i = 0; i < childCount; i++ ){
|
|
|
|
childTree = CFTreeGetChildAtIndex( tree, i );
|
|
childNode = CFXMLTreeGetNode( childTree );
|
|
childName = CFXMLNodeGetString( childNode );
|
|
|
|
// Is this it?
|
|
if( CFStringCompare( name, childName, NULL ) == kCFCompareEqualTo )
|
|
return childTree;
|
|
|
|
// If child is an element, search recursively
|
|
if( CFXMLNodeGetTypeCode( childNode ) == kCFXMLNodeTypeElement ){
|
|
|
|
descTree = XMLTreeDescendentNamed( name, childTree );
|
|
|
|
// Got a match?
|
|
if( descTree != NULL )
|
|
return descTree;
|
|
|
|
} // end if: element node type
|
|
|
|
} // end for
|
|
|
|
return NULL;
|
|
} // end XMLTreeDescendentNamed:
|
|
|