diff options
Diffstat (limited to 'Source/SPXMLExporter.m')
-rw-r--r-- | Source/SPXMLExporter.m | 291 |
1 files changed, 144 insertions, 147 deletions
diff --git a/Source/SPXMLExporter.m b/Source/SPXMLExporter.m index de43560e..0c060a55 100644 --- a/Source/SPXMLExporter.m +++ b/Source/SPXMLExporter.m @@ -58,73 +58,104 @@ */ - (void)main { - @try { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSArray *xmlRow = nil; - NSString *dataConversionString = nil; - MCPStreamingResult *streamingResult = nil; - - NSMutableArray *xmlTags = [NSMutableArray array]; - NSMutableString *xmlString = [NSMutableString string]; - NSMutableString *xmlItem = [NSMutableString string]; - - NSUInteger xmlRowCount = 0; - NSUInteger i, totalRows, currentRowIndex, lastProgressValue, currentPoolDataLength; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSArray *xmlRow = nil; + NSString *dataConversionString = nil; + MCPStreamingResult *streamingResult = nil; + + NSMutableArray *xmlTags = [NSMutableArray array]; + NSMutableString *xmlString = [NSMutableString string]; + NSMutableString *xmlItem = [NSMutableString string]; + + NSUInteger xmlRowCount = 0; + NSUInteger i, totalRows, currentRowIndex, lastProgressValue, currentPoolDataLength; + + // Check to see if we have at least a table name or data array + if ((![self xmlTableName]) && (![self xmlDataArray]) || + ([[self xmlTableName] isEqualToString:@""]) && ([[self xmlDataArray] count] == 0)) + { + [pool release]; + return; + } + + // Inform the delegate that the export process is about to begin + [delegate performSelectorOnMainThread:@selector(xmlExportProcessWillBegin:) withObject:self waitUntilDone:NO]; + + // Mark the process as running + [self setExportProcessIsRunning:YES]; + + lastProgressValue = 0; + + // Make a streaming request for the data if the data array isn't set + if ((![self xmlDataArray]) && [self xmlTableName]) { + totalRows = [[[[connection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@", [[self xmlTableName] backtickQuotedString]]] fetchRowAsArray] objectAtIndex:0] integerValue]; + streamingResult = [connection streamingQueryString:[NSString stringWithFormat:@"SELECT * FROM %@", [[self xmlTableName] backtickQuotedString]] useLowMemoryBlockingStreaming:[self exportUsingLowMemoryBlockingStreaming]]; + } + else { + totalRows = [[self xmlDataArray] count]; + } + + // Set up an array of encoded field names as opening and closing tags + xmlRow = ([self xmlDataArray]) ? [[self xmlDataArray] objectAtIndex:0] : [streamingResult fetchFieldNames]; + + for (i = 0; i < [xmlRow count]; i++) + { + [xmlTags addObject:[NSMutableArray array]]; - // Check to see if we have at least a table name or data array - if ((![self xmlTableName]) && (![self xmlDataArray]) || - ([[self xmlTableName] isEqualToString:@""]) && ([[self xmlDataArray] count] == 0)) - { + [[xmlTags objectAtIndex:i] addObject:[NSString stringWithFormat:@"\t\t<%@>", [[[xmlRow objectAtIndex:i] description] HTMLEscapeString]]]; + [[xmlTags objectAtIndex:i] addObject:[NSString stringWithFormat:@"</%@>\n", [[[xmlRow objectAtIndex:i] description] HTMLEscapeString]]]; + } + + [[self exportOutputFileHandle] writeData:[xmlString dataUsingEncoding:[self exportOutputEncoding]]]; + + // Write an opening tag in the form of the table name + [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"\t<%@>\n", ([self xmlTableName]) ? [[self xmlTableName] HTMLEscapeString] : @"custom"] dataUsingEncoding:[self exportOutputEncoding]]]; + + // Set up the starting row, which is 0 for streaming result sets and + // 1 for supplied arrays which include the column headers as the first row. + currentRowIndex = 0; + + if ([self xmlDataArray]) currentRowIndex++; + + // Drop into the processing loop + NSAutoreleasePool *xmlExportPool = [[NSAutoreleasePool alloc] init]; + + currentPoolDataLength = 0; + + while (1) + { + // Check for cancellation flag + if ([self isCancelled]) { + if (streamingResult) { + [connection cancelCurrentQuery]; + [streamingResult cancelResultLoad]; + } + + [xmlExportPool release]; [pool release]; + return; } - - // Inform the delegate that the export process is about to begin - [delegate performSelectorOnMainThread:@selector(xmlExportProcessWillBegin:) withObject:self waitUntilDone:NO]; - // Mark the process as running - [self setExportProcessIsRunning:YES]; - - lastProgressValue = 0; - - // Make a streaming request for the data if the data array isn't set - if ((![self xmlDataArray]) && [self xmlTableName]) { - totalRows = [[[[connection queryString:[NSString stringWithFormat:@"SELECT COUNT(1) FROM %@", [[self xmlTableName] backtickQuotedString]]] fetchRowAsArray] objectAtIndex:0] integerValue]; - streamingResult = [connection streamingQueryString:[NSString stringWithFormat:@"SELECT * FROM %@", [[self xmlTableName] backtickQuotedString]] useLowMemoryBlockingStreaming:[self exportUsingLowMemoryBlockingStreaming]]; - } + // Retrieve the next row from the supplied data, either directly from the array... + if ([self xmlDataArray]) { + xmlRow = NSArrayObjectAtIndex([self xmlDataArray], currentRowIndex); + } + // Or by reading an appropriate row from the streaming result else { - totalRows = [[self xmlDataArray] count]; - } - - // Set up an array of encoded field names as opening and closing tags - xmlRow = ([self xmlDataArray]) ? [[self xmlDataArray] objectAtIndex:0] : [streamingResult fetchFieldNames]; - - for (i = 0; i < [xmlRow count]; i++) - { - [xmlTags addObject:[NSMutableArray array]]; + xmlRow = [streamingResult fetchNextRowAsArray]; - [[xmlTags objectAtIndex:i] addObject:[NSString stringWithFormat:@"\t\t<%@>", [[[xmlRow objectAtIndex:i] description] HTMLEscapeString]]]; - [[xmlTags objectAtIndex:i] addObject:[NSString stringWithFormat:@"</%@>\n", [[[xmlRow objectAtIndex:i] description] HTMLEscapeString]]]; + if (!xmlRow) break; } - [[self exportOutputFileHandle] writeData:[xmlString dataUsingEncoding:[self exportOutputEncoding]]]; - - // Write an opening tag in the form of the table name - [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"\t<%@>\n", ([self xmlTableName]) ? [[self xmlTableName] HTMLEscapeString] : @"custom"] dataUsingEncoding:[self exportOutputEncoding]]]; + // Get the cell count if we don't already have it stored + if (!xmlRowCount) xmlRowCount = [xmlRow count]; - // Set up the starting row, which is 0 for streaming result sets and - // 1 for supplied arrays which include the column headers as the first row. - currentRowIndex = 0; + // Construct the row + [xmlString setString:@"\t<row>\n"]; - if ([self xmlDataArray]) currentRowIndex++; - - // Drop into the processing loop - NSAutoreleasePool *xmlExportPool = [[NSAutoreleasePool alloc] init]; - - currentPoolDataLength = 0; - - while (1) + for (i = 0; i < xmlRowCount; i++) { // Check for cancellation flag if ([self isCancelled]) { @@ -139,109 +170,75 @@ return; } - // Retrieve the next row from the supplied data, either directly from the array... - if ([self xmlDataArray]) { - xmlRow = NSArrayObjectAtIndex([self xmlDataArray], currentRowIndex); - } - // Or by reading an appropriate row from the streaming result - else { - xmlRow = [streamingResult fetchNextRowAsArray]; - - if (!xmlRow) break; - } - - // Get the cell count if we don't already have it stored - if (!xmlRowCount) xmlRowCount = [xmlRow count]; - - // Construct the row - [xmlString setString:@"\t<row>\n"]; - - for (i = 0; i < xmlRowCount; i++) - { - // Check for cancellation flag - if ([self isCancelled]) { - if (streamingResult) { - [connection cancelCurrentQuery]; - [streamingResult cancelResultLoad]; - } - - [xmlExportPool release]; - [pool release]; - - return; - } + // Retrieve the contents of this tag + if ([NSArrayObjectAtIndex(xmlRow, i) isKindOfClass:[NSData class]]) { + dataConversionString = [[NSString alloc] initWithData:NSArrayObjectAtIndex(xmlRow, i) encoding:[self exportOutputEncoding]]; - // Retrieve the contents of this tag - if ([NSArrayObjectAtIndex(xmlRow, i) isKindOfClass:[NSData class]]) { - dataConversionString = [[NSString alloc] initWithData:NSArrayObjectAtIndex(xmlRow, i) encoding:[self exportOutputEncoding]]; - - if (dataConversionString == nil) { - dataConversionString = [[NSString alloc] initWithData:NSArrayObjectAtIndex(xmlRow, i) encoding:NSASCIIStringEncoding]; - } - - [xmlItem setString:[NSString stringWithString:dataConversionString]]; - [dataConversionString release]; - } - else { - [xmlItem setString:[NSArrayObjectAtIndex(xmlRow, i) description]]; + if (dataConversionString == nil) { + dataConversionString = [[NSString alloc] initWithData:NSArrayObjectAtIndex(xmlRow, i) encoding:NSASCIIStringEncoding]; } - // Add the opening and closing tag and the contents to the XML string - [xmlString appendString:NSArrayObjectAtIndex(NSArrayObjectAtIndex(xmlTags, i), 0)]; - [xmlString appendString:[xmlItem HTMLEscapeString]]; - [xmlString appendString:NSArrayObjectAtIndex(NSArrayObjectAtIndex(xmlTags, i), 1)]; - } - - [xmlString appendString:@"\t</row>\n"]; - - // Record the total length for use with pool flushing - currentPoolDataLength += [xmlString length]; - - // Write the row to the filehandle - [[self exportOutputFileHandle] writeData:[xmlString dataUsingEncoding:[self exportOutputEncoding]]]; - - // Update the progress counter and progress bar - currentRowIndex++; - - // Update the progress - if (totalRows && (currentRowIndex * ([self exportMaxProgress] / totalRows)) > lastProgressValue) { - - NSInteger progress = (currentRowIndex * ([self exportMaxProgress] / totalRows)); - - [self setExportProgressValue:progress]; - - lastProgressValue = progress; - } - - // Inform the delegate that the export's progress has been updated - [delegate performSelectorOnMainThread:@selector(xmlExportProcessProgressUpdated:) withObject:self waitUntilDone:NO]; - - // Drain the autorelease pool as required to keep memory usage low - if (currentPoolDataLength > 250000) { - [xmlExportPool release]; - xmlExportPool = [[NSAutoreleasePool alloc] init]; + [xmlItem setString:[NSString stringWithString:dataConversionString]]; + [dataConversionString release]; + } + else { + [xmlItem setString:[NSArrayObjectAtIndex(xmlRow, i) description]]; } - // If an array was supplied and we've processed all rows, break - if ([self xmlDataArray] && totalRows == currentRowIndex) break; + // Add the opening and closing tag and the contents to the XML string + [xmlString appendString:NSArrayObjectAtIndex(NSArrayObjectAtIndex(xmlTags, i), 0)]; + [xmlString appendString:[xmlItem HTMLEscapeString]]; + [xmlString appendString:NSArrayObjectAtIndex(NSArrayObjectAtIndex(xmlTags, i), 1)]; } - // Write the closing tag for the table - [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"\t</%@>\n\n", ([self xmlTableName]) ? [[self xmlTableName] HTMLEscapeString] : @"custom"] dataUsingEncoding:[self exportOutputEncoding]]]; + [xmlString appendString:@"\t</row>\n"]; - // Write data to disk - [[self exportOutputFileHandle] synchronizeFile]; + // Record the total length for use with pool flushing + currentPoolDataLength += [xmlString length]; - // Mark the process as not running - [self setExportProcessIsRunning:NO]; + // Write the row to the filehandle + [[self exportOutputFileHandle] writeData:[xmlString dataUsingEncoding:[self exportOutputEncoding]]]; - // Inform the delegate that the export process is complete - [delegate performSelectorOnMainThread:@selector(xmlExportProcessComplete:) withObject:self waitUntilDone:NO]; + // Update the progress counter and progress bar + currentRowIndex++; - [xmlExportPool release]; - [pool release]; + // Update the progress + if (totalRows && (currentRowIndex * ([self exportMaxProgress] / totalRows)) > lastProgressValue) { + + NSInteger progress = (currentRowIndex * ([self exportMaxProgress] / totalRows)); + + [self setExportProgressValue:progress]; + + lastProgressValue = progress; + } + + // Inform the delegate that the export's progress has been updated + [delegate performSelectorOnMainThread:@selector(xmlExportProcessProgressUpdated:) withObject:self waitUntilDone:NO]; + + // Drain the autorelease pool as required to keep memory usage low + if (currentPoolDataLength > 250000) { + [xmlExportPool release]; + xmlExportPool = [[NSAutoreleasePool alloc] init]; + } + + // If an array was supplied and we've processed all rows, break + if ([self xmlDataArray] && totalRows == currentRowIndex) break; } - @catch (NSException *e) { } + + // Write the closing tag for the table + [[self exportOutputFileHandle] writeData:[[NSString stringWithFormat:@"\t</%@>\n\n", ([self xmlTableName]) ? [[self xmlTableName] HTMLEscapeString] : @"custom"] dataUsingEncoding:[self exportOutputEncoding]]]; + + // Write data to disk + [[self exportOutputFileHandle] synchronizeFile]; + + // Mark the process as not running + [self setExportProcessIsRunning:NO]; + + // Inform the delegate that the export process is complete + [delegate performSelectorOnMainThread:@selector(xmlExportProcessComplete:) withObject:self waitUntilDone:NO]; + + [xmlExportPool release]; + [pool release]; } /** |