/** Implementation for NSXMLParser for GNUStep Copyright (C) 2004 Free Software Foundation, Inc. Written by: Richard Frith-Macdonald Date: May 2004 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. */ #include "config.h" #include #include #include #include #include #include NSString* const NSXMLParserErrorDomain = @"NSXMLParserErrorDomain"; #if defined(HAVE_LIBXML) /* We support a strict libxml2 based parser ... but sometimes we need a * sloppier parser which copes with bad XML generated by Apple's software, * so we call the sloppy parser GSSloppyXMLParser. */ #define SloppyXMLParser GSSloppyXMLParser @interface GSSloppyXMLParser : NSXMLParser @end #include @interface NSXMLSAXHandler : GSSAXHandler { @public id _delegate; id _owner; NSError *_lastError; BOOL _shouldProcessNamespaces; BOOL _shouldReportNamespacePrefixes; BOOL _shouldResolveExternalEntities; } - (void) _setOwner: (id)owner; @end @implementation NSXMLSAXHandler - (void) endDocument { [_delegate parserDidEndDocument: _owner]; } - (void) startDocument { [_delegate parserDidStartDocument: _owner]; } - (void) startElement: (NSString*)elementName prefix: (NSString*)prefix href: (NSString*)href attributes: (NSMutableDictionary*)elementAttributes { if (_shouldProcessNamespaces) { [_delegate parser: _owner didStartElement: elementName namespaceURI: href qualifiedName: prefix attributes: elementAttributes]; } else { [_delegate parser: _owner didStartElement: elementName namespaceURI: nil qualifiedName: nil attributes: elementAttributes]; } } - (void) endElement: (NSString*) elementName prefix: (NSString*)prefix href: (NSString*)href { if (_shouldProcessNamespaces) { [_delegate parser: _owner didEndElement: elementName namespaceURI: href qualifiedName: prefix]; } else { [_delegate parser: _owner didEndElement: elementName namespaceURI: nil qualifiedName: nil]; } } - (void) attribute: (NSString*) name value: (NSString*)value { // FIXME } - (void) characters: (NSString*)string { [_delegate parser: _owner foundCharacters: string]; } - (void) ignoreWhitespace: (NSString*) ch { [_delegate parser: _owner foundIgnorableWhitespace: ch]; } - (void) processInstruction: (NSString*)targetName data: (NSString*)PIdata { [_delegate parser: _owner foundProcessingInstructionWithTarget: targetName data: PIdata]; } - (void) comment: (NSString*) value { [_delegate parser: _owner foundComment: value]; } - (void) cdataBlock: (NSData*)value { [_delegate parser: _owner foundCDATA: value]; } /** * Called to return the filename from which an entity should be loaded. */ - (NSString*) loadEntity: (NSString*)publicId at: (NSString*)location { return nil; } /** * An old global namespace has been parsed. */ - (void) namespaceDecl: (NSString*)name href: (NSString*)href prefix: (NSString*)prefix { } - (void) notationDecl: (NSString*)name public: (NSString*)publicId system: (NSString*)systemId { [_delegate parser: _owner foundNotationDeclarationWithName: name publicID: publicId systemID: systemId]; } /** * An entity definition has been parsed. */ - (void) entityDecl: (NSString*)name type: (int)type public: (NSString*)publicId system: (NSString*)systemId content: (NSString*)content { } - (void) attributeDecl: (NSString*)nameElement name: (NSString*)name type: (int)type typeDefValue: (int)defType defaultValue: (NSString*)value { [_delegate parser: _owner foundAttributeDeclarationWithName: name forElement: nameElement type: nil // FIXME defaultValue: value]; } - (void) elementDecl: (NSString*)name type: (int)type { [_delegate parser: _owner foundElementDeclarationWithName: name model: nil]; // FIXME } /** * What to do when an unparsed entity declaration is parsed. */ - (void) unparsedEntityDecl: (NSString*)name public: (NSString*)publicId system: (NSString*)systemId notationName: (NSString*)notation { } /** * Called when an entity reference is detected. */ - (void) reference: (NSString*) name { } /** * An old global namespace has been parsed. */ - (void) globalNamespace: (NSString*)name href: (NSString*)href prefix: (NSString*)prefix { } /** * Called when a warning message needs to be output. */ - (void) warning: (NSString*)e { GSPrintf(stderr, @"%@", e); } - (void) error: (NSString*)e { NSError *error; NSDictionary *d; d = [NSDictionary dictionaryWithObjectsAndKeys: e, NSLocalizedDescriptionKey, nil]; error = [NSError errorWithDomain: NSXMLParserErrorDomain code: 0 userInfo: d]; ASSIGN(_lastError, error); [_delegate parser: _owner parseErrorOccurred: error]; } - (void) fatalError: (NSString*)e { [self error: e]; } - (void) warning: (NSString*)e colNumber: (int)colNumber lineNumber: (int)lineNumber { e = [NSString stringWithFormat: @"at line: %d column: %d ... %@", lineNumber, colNumber, e]; [self warning: e]; } - (void) error: (NSString*)e colNumber: (int)colNumber lineNumber: (int)lineNumber { e = [NSString stringWithFormat: @"at line: %d column: %d ... %@", lineNumber, colNumber, e]; [self error: e]; } - (void) fatalError: (NSString*)e colNumber: (int)colNumber lineNumber: (int)lineNumber { e = [NSString stringWithFormat: @"at line: %d column: %d ... %@", lineNumber, colNumber, e]; [self fatalError: e]; } - (int) hasInternalSubset { return 0; } - (BOOL) internalSubset: (NSString*)name externalID: (NSString*)externalID systemID: (NSString*)systemID { return NO; } - (int) hasExternalSubset { return 0; } - (BOOL) externalSubset: (NSString*)name externalID: (NSString*)externalID systemID: (NSString*)systemID { return NO; } - (void*) getEntity: (NSString*)name { return 0; } - (void*) getParameterEntity: (NSString*)name { return 0; } - (void) _setOwner: (id)owner { ASSIGN(_owner, owner); } @end @implementation NSXMLParser #define myParser ((GSXMLParser*)_parser) #define myHandler ((NSXMLSAXHandler*)_handler) - (void) abortParsing { NSDictionary *d; NSString *e; NSError *error; e = @"Parsing aborted"; d = [NSDictionary dictionaryWithObjectsAndKeys: e, NSLocalizedDescriptionKey, nil]; error = [NSError errorWithDomain: NSXMLParserErrorDomain code: 0 userInfo: d]; ASSIGN(myHandler->_lastError, error); [myHandler->_delegate parser: myHandler->_owner parseErrorOccurred: error]; [myParser abortParsing]; } - (void) dealloc { DESTROY(_parser); DESTROY(_handler); [super dealloc]; } - (id) delegate { return myHandler->_delegate; } - (id) initWithContentsOfURL: (NSURL*)anURL { NSData *d = [NSData dataWithContentsOfURL: anURL]; if (d == nil) { DESTROY(self); } else { self = [self initWithData: d]; } return self; } - (id) initWithData: (NSData*)data { _handler = [NSXMLSAXHandler new]; [myHandler _setOwner: self]; _parser = [[GSXMLParser alloc] initWithSAXHandler: myHandler withData: data]; return self; } - (BOOL) parse { BOOL result; result = [[myHandler parser] parse]; return result; } - (NSError*) parserError { return nil; // FIXME } - (void) setDelegate: (id)delegate { myHandler->_delegate = delegate; } - (void) setShouldProcessNamespaces: (BOOL)aFlag { myHandler->_shouldProcessNamespaces = aFlag; } - (void) setShouldReportNamespacePrefixes: (BOOL)aFlag { myHandler->_shouldReportNamespacePrefixes = aFlag; } - (void) setShouldResolveExternalEntities: (BOOL)aFlag { myHandler->_shouldResolveExternalEntities = aFlag; } - (BOOL) shouldProcessNamespaces { return myHandler->_shouldProcessNamespaces; } - (BOOL) shouldReportNamespacePrefixes { return myHandler->_shouldReportNamespacePrefixes; } - (BOOL) shouldResolveExternalEntities { return myHandler->_shouldResolveExternalEntities; } @end @implementation NSXMLParser (NSXMLParserLocatorAdditions) - (int) columnNumber { return [myParser columnNumber]; } - (int) lineNumber { return [myParser lineNumber]; } - (NSString*) publicID { return [myParser publicID]; } - (NSString*) systemID { return [myParser systemID]; } @end #else /* We have no strict libxml based parser, so we use the sloppy parser * as the normal NSXMLParser and create a GSSloppyXMLParser subclass * so that we can still specify GSSloppyXMLParser in other files. */ #define SloppyXMLParser NSXMLParser @interface GSSloppyXMLParser : NSXMLParser @end @implementation GSSloppyXMLParser @end #endif @implementation NSString (NSXMLParser) - (NSString *) _stringByExpandingXMLEntities { NSMutableString *t=[NSMutableString stringWithString: self]; [t replaceOccurrencesOfString: @"&" withString: @"&" options: 0 range: NSMakeRange(0, [t length])]; // must be first! [t replaceOccurrencesOfString: @"<" withString: @"<" options: 0 range: NSMakeRange(0, [t length])]; [t replaceOccurrencesOfString: @">" withString: @">" options: 0 range: NSMakeRange(0, [t length])]; [t replaceOccurrencesOfString: @"\"" withString: @""" options: 0 range: NSMakeRange(0, [t length])]; [t replaceOccurrencesOfString: @"'" withString: @"'" options: 0 range: NSMakeRange(0, [t length])]; return t; } @end static NSString *UTF8STR(const void *ptr, int len) { NSString *s; s = [[NSString alloc] initWithBytes: ptr length: len encoding: NSUTF8StringEncoding]; if (s == nil) NSLog(@"could not convert to UTF8 string! bytes=%08x len=%d", ptr, len); return AUTORELEASE(s); } typedef struct NSXMLParserIvarsType { NSMutableArray *tagPath; // hierarchy of tags NSData *data; NSError *error; const unsigned char *cp; // character pointer const unsigned char *cend; // end of data int line; // current line (counts from 0) int column; // current column (counts from 0) BOOL abort; // abort parse loop BOOL shouldProcessNamespaces; BOOL shouldReportNamespacePrefixes; BOOL shouldResolveExternalEntities; BOOL acceptHTML; // be lazy with bad tag nesting } NSXMLParserIvars; @implementation SloppyXMLParser #define EXTRA_DEBUG 0 typedef struct { @defs(NSXMLParser) } *xp; #define _parser (((xp)self)->_parser) #define _handler (((xp)self)->_handler) #define this ((NSXMLParserIvars*)_parser) #define _del ((id)_handler) - (void) abortParsing { this->abort = YES; } - (int) columnNumber { return this->column; } - (void) dealloc { if (this != 0) { RELEASE(this->data); RELEASE(this->error); RELEASE(this->tagPath); NSZoneFree([self zone], this); _parser = 0; _handler = 0; } [super dealloc]; } - (id) delegate { return _del; } - (id) initWithContentsOfURL: (NSURL *)anURL { return [self initWithData: [NSData dataWithContentsOfURL: anURL]]; } - (id) initWithData: (NSData *)data { if (data == nil) { DESTROY(self); } else { self = [super init]; if (self) { _parser = NSZoneMalloc([self zone], sizeof(NSXMLParserIvars)); memset(_parser, '\0', sizeof(NSXMLParserIvars)); this->data = [data copy]; this->tagPath = [[NSMutableArray alloc] init]; this->cp = [this->data bytes]; this->cend = this->cp + [this->data length]; } } return self; } - (int) lineNumber { return this->line; } - (void) setDelegate: (id)delegate { _handler = delegate; } - (NSError *) parserError { return this->error; } - (NSArray *) _tagPath { return this->tagPath; } #define cget() ((this->cp < this->cend)?(this->column++, *this->cp++): -1) - (BOOL) _parseError: (NSString *)message { #if EXTRA_DEBUG NSLog(@"XML parseError: %@", message); #endif NSError *err = nil; ASSIGN(this->error, err); this->abort = YES; // break look if ([_del respondsToSelector: @selector(parser:parseErrorOccurred:)]) [_del parser: self parseErrorOccurred: this->error]; // pass error return NO; } - (void) _processTag: (NSString *)tag isEnd: (BOOL)flag withAttributes: (NSDictionary *)attributes { if (this->acceptHTML) tag = [tag lowercaseString]; // not case sensitive if (!flag) { if ([tag isEqualToString: @"?xml"]) { #if EXTRA_DEBUG NSLog(@"parserDidStartDocument: "); #endif if ([_del respondsToSelector: @selector(parserDidStartDocument:)]) [_del parserDidStartDocument: self]; return; } if ([tag hasPrefix: @"?"]) { #if EXTRA_DEBUG NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes); #endif // parser: foundProcessingInstructionWithTarget: data: return; } if ([tag isEqualToString: @"!DOCTYPE"]) { #if EXTRA_DEBUG NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes); #endif return; } if ([tag isEqualToString: @"!ENTITY"]) { #if EXTRA_DEBUG NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes); #endif return; } if ([tag isEqualToString: @"!CDATA"]) { // pass through as NSData // parser: foundCDATA: #if EXTRA_DEBUG NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes); #endif return; } [this->tagPath addObject: tag]; // push on stack if ([_del respondsToSelector: @selector(parser:didStartElement:namespaceURI:qualifiedName:attributes:)]) [_del parser: self didStartElement: tag namespaceURI: nil qualifiedName: nil attributes: attributes]; } else { // closing tag if (this->acceptHTML) { // lazily close any missing tags on stack while ([this->tagPath count] > 0 && ![[this->tagPath lastObject] isEqualToString: tag]) { if ([_del respondsToSelector: @selector(parser:didEndElement:namespaceURI:qualifiedName:)]) [_del parser: self didEndElement: [this->tagPath lastObject] namespaceURI: nil qualifiedName: nil]; [this->tagPath removeLastObject]; // pop from stack } if ([this->tagPath count] == 0) return; // ignore closing tag without matching open... } else if (![[this->tagPath lastObject] isEqualToString: tag]) { [self _parseError: [NSString stringWithFormat: @"tag nesting error ( expected, found)", [this->tagPath lastObject], tag]]; return; } if ([_del respondsToSelector: @selector(parser:didEndElement:namespaceURI:qualifiedName:)]) [_del parser: self didEndElement: tag namespaceURI: nil qualifiedName: nil]; [this->tagPath removeLastObject]; // pop from stack } } - (NSString *) _entity { // parse &xxx; sequence int c; const unsigned char *ep = this->cp; // should be position behind & int len; unsigned int val; NSString *entity; do { c = cget(); } while (c != EOF && c != '<' && c != ';'); if (c != ';') return nil; // invalid sequence - end of file or missing ; before next tag len = this->cp - ep - 1; if (*ep == '#') { // &#ddd; or &#xhh; // !!! ep+1 is not 0-terminated - but by ;!! if (sscanf((char *)ep+1, "x%x;", &val)) return [NSString stringWithFormat: @"%C", val]; // &#xhh; hex value else if (sscanf((char *)ep+1, "%d;", &val)) return [NSString stringWithFormat: @"%C", val]; // &ddd; decimal value } else { // the five predefined entities if (len == 3 && strncmp((char *)ep, "amp", len) == 0) return @"&"; if (len == 2 && strncmp((char *)ep, "lt", len) == 0) return @"<"; if (len == 2 && strncmp((char *)ep, "gt", len) == 0) return @">"; if (len == 4 && strncmp((char *)ep, "quot", len) == 0) return @"\""; if (len == 4 && strncmp((char *)ep, "apos", len) == 0) return @"'"; } entity = UTF8STR(ep, len); #if 1 NSLog(@"NSXMLParser: unrecognized entity: &%@;", entity); #endif // entity=[entitiesTable objectForKey: entity]; // look up string in entity translation table if (!entity) entity=@"&??;"; // unknown entity return entity; } - (NSString *) _qarg { // get argument (might be quoted) const unsigned char *ap = --this->cp; // argument start pointer int c = cget(); // refetch first character #if EXTRA_DEBUG NSLog(@"_qarg: %02x %c", c, isprint(c)?c: ' '); #endif if (c == '\"') { // quoted argument do { c = cget(); if (c == EOF) return nil; // unterminated! } while (c != '\"'); return UTF8STR(ap + 1, this->cp - ap - 2); } if (c == '\'') { // apostrophed argument do { c = cget(); if (c == EOF) return nil; // unterminated! } while (c != '\''); return UTF8STR(ap + 1, this->cp - ap - 2); } if (!this->acceptHTML) ; // strict XML requires quoting (?) while (!isspace(c) && c != '>' && c != '/' && c != '?' && c != '=' &&c != EOF) c = cget(); this->cp--; // go back to terminating character return UTF8STR(ap, this->cp - ap); } - (BOOL) parse { // read XML (or HTML) file const unsigned char *vp = this->cp; // value pointer int c; if (!this->acceptHTML && (this->cend - this->cp < 6 || strncmp((char *)this->cp, " preamble"]; } c = cget(); // get first character while (!this->abort) { // parse next element #if EXTRA_DEBUG NSLog(@"_nextelement %02x %c", c, isprint(c)?c: ' '); #endif switch(c) { case '\r': this->column = 0; break; case '\n': this->line++; this->column = 0; case EOF: case '<': case '&': { // push out any characters that have been collected so far if (this->cp - vp > 1) { // check for whitespace only - might set/reset a flag to indicate so if ([_del respondsToSelector: @selector(parser: foundCharacters: )]) [_del parser: self foundCharacters: UTF8STR(vp, this->cp - vp - 1)]; vp = this->cp; } } } switch(c) { default: c = cget(); // just collect until we push out (again) continue; case EOF: // end of file { if ([this->tagPath count] != 0) { if (!this->acceptHTML) return [self _parseError: @"unexpected end of file"]; // strict XML nesting error while ([this->tagPath count] > 0) { // lazily close all open tags if ([_del respondsToSelector: @selector(parser: didEndElement: namespaceURI: qualifiedName: )]) [_del parser: self didEndElement: [this->tagPath lastObject] namespaceURI: nil qualifiedName: nil]; [this->tagPath removeLastObject]; // pop from stack } } #if EXTRA_DEBUG NSLog(@"parserDidEndDocument: "); #endif if ([_del respondsToSelector: @selector(parserDidEndDocument: )]) [_del parserDidEndDocument: self]; return YES; } case '&': { // escape entity begins NSString *entity=[self _entity]; if (!entity) return [self _parseError: @"empty entity name"]; if ([_del respondsToSelector: @selector(parser: foundCharacters: )]) [_del parser: self foundCharacters: entity]; vp = this->cp; // next value sequence starts here c = cget(); // first character behind ; continue; } case '<': { // tag begins NSString *tag; NSMutableDictionary *parameters; NSString *arg; const unsigned char *tp = this->cp; // tag pointer if (this->cp < this->cend-3 && strncmp((char *)this->cp, "!--", 3) == 0) { // start of comment skip all characters until "-->" this->cp+=3; while (this->cp < this->cend-3 && strncmp((char *)this->cp, "-->", 3) != 0) this->cp++; // search // if _del responds to parser: foundComment: // convert to string (tp+4 ... cp) this->cp+=3; // might go beyond cend but does not care vp = this->cp; // value might continue c = cget(); // get first character behind comment continue; } c = cget(); // get first character of tag if (c == '/') c = cget(); // closing tag should process this tag in a special way so that e.g. is read as a single tag! // to do this properly, we need a notion of comments and quoted string constants... } while (!isspace(c) && c != '>' && (c != '/') && (c != '?')) c = cget(); // scan tag until we find a delimiting character if (*tp == '/') tag = UTF8STR(tp + 1, this->cp - tp - 2); // don't include / and delimiting character else tag = UTF8STR(tp, this->cp - tp - 1); // don't include delimiting character #if EXTRA_DEBUG NSLog(@"tag=%@ - %02x %c", tag, c, isprint(c)?c: ' '); #endif parameters=[NSMutableDictionary dictionaryWithCapacity: 5]; while (c != EOF) { // collect arguments if (c == '/' && *tp != '/') { // appears to be a /> c = cget(); if (c != '>') return [self _parseError: @""]; [self _processTag: tag isEnd: NO withAttributes: parameters]; // opening tag [self _processTag: tag isEnd: YES withAttributes: nil]; // closing tag break; // done } if (c == '?' && *tp == '?') { // appears to be a ?> c = cget(); if (c != '>') return [self _parseError: @""]; // process [self _processTag: tag isEnd: NO withAttributes: parameters]; // single break; // done } while (isspace(c)) // this->should also allow for line break and tab c = cget(); if (c == '>') { [self _processTag: tag isEnd: (*tp=='/') withAttributes: parameters]; // handle tag break; } arg=[self _qarg]; // get next argument (eats up to /, ?, >, =, space) #if EXTRA_DEBUG NSLog(@"arg=%@", arg); #endif if (!this->acceptHTML && [arg length] == 0) return [self _parseError: @"empty attribute name"]; c = cget(); // get delimiting character if (c == '=') { // explicit assignment c = cget(); // skip = [parameters setObject: [self _qarg] forKey: arg]; c = cget(); // get character behind qarg value } else // implicit [parameters setObject: @"" forKey: arg]; } vp = this->cp; // prepare for next value c = cget(); // skip > and fetch next character } } } return [self _parseError: @"this->aborted"]; // this->aborted } - (BOOL) acceptsHTML { return this->acceptHTML; } - (BOOL) shouldProcessNamespaces { return this->shouldProcessNamespaces; } - (BOOL) shouldReportNamespacePrefixes { return this->shouldReportNamespacePrefixes; } - (BOOL) shouldResolveExternalEntities { return this->shouldResolveExternalEntities; } - (void) setShouldProcessNamespaces: (BOOL)aFlag { this->shouldProcessNamespaces = aFlag; } - (void) setShouldReportNamespacePrefixes: (BOOL)aFlag { this->shouldReportNamespacePrefixes = aFlag; } - (void) setShouldResolveExternalEntities: (BOOL)aFlag { this->shouldProcessNamespaces = aFlag; } - (void) _setAcceptHTML: (BOOL) flag { this->acceptHTML = flag; } - (NSString *) publicID { return [self notImplemented: _cmd]; } - (NSString *) systemID { return [self notImplemented: _cmd]; } @end @implementation NSObject (NSXMLParserDelegateEventAdditions) - (NSData*) parser: (NSXMLParser*)aParser resolveExternalEntityName: (NSString*)aName systemID: (NSString*)aSystemID { return nil; } - (void) parser: (NSXMLParser*)aParser didEndElement: (NSString*)anElementName namespaceURI: (NSString*)aNamespaceURI qualifiedName: (NSString*)aQualifierName { } - (void) parser: (NSXMLParser*)aParser didEndMappingPrefix: (NSString*)aPrefix { } - (void) parser: (NSXMLParser*)aParser didStartElement: (NSString*)anElementName namespaceURI: (NSString*)aNamespaceURI qualifiedName: (NSString*)aQualifierName attributes: (NSDictionary*)anAttributeDict { } - (void) parser: (NSXMLParser*)aParser didStartMappingPrefix: (NSString*)aPrefix toURI: (NSString*)aNamespaceURI { } - (void) parser: (NSXMLParser*)aParser foundAttributeDeclarationWithName: (NSString*)anAttributeName forElement: (NSString*)anElementName type: (NSString*)aType defaultValue: (NSString*)aDefaultValue { } - (void) parser: (NSXMLParser*)aParser foundCDATA: (NSData*)aBlock { } - (void) parser: (NSXMLParser*)aParser foundCharacters: (NSString*)aString { } - (void) parser: (NSXMLParser*)aParser foundComment: (NSString*)aComment { } - (void) parser: (NSXMLParser*)aParser foundElementDeclarationWithName: (NSString*)anElementName model: (NSString*)aModel { } - (void) parser: (NSXMLParser*)aParser foundExternalEntityDeclarationWithName: (NSString*)aName publicID: (NSString*)aPublicID systemID: (NSString*)aSystemID { } - (void) parser: (NSXMLParser*)aParser foundIgnorableWhitespace: (NSString*)aWhitespaceString { } - (void) parser: (NSXMLParser*)aParser foundInternalEntityDeclarationWithName: (NSString*)aName value: (NSString*)aValue { } - (void) parser: (NSXMLParser*)aParser foundNotationDeclarationWithName: (NSString*)aName publicID: (NSString*)aPublicID systemID: (NSString*)aSystemID { } - (void) parser: (NSXMLParser*)aParser foundProcessingInstructionWithTarget: (NSString*)aTarget data: (NSString*)aData { } - (void) parser: (NSXMLParser*)aParser foundUnparsedEntityDeclarationWithName: (NSString*)aName publicID: (NSString*)aPublicID systemID: (NSString*)aSystemID notationName: (NSString*)aNotationName { } - (void) parser: (NSXMLParser*)aParser parseErrorOccurred: (NSError*)anError { } - (void) parser: (NSXMLParser*)aParser validationErrorOccurred: (NSError*)anError { } - (void) parserDidEndDocument: (NSXMLParser*)aParser { } - (void) parserDidStartDocument: (NSXMLParser*)aParser { } @end