From a9be9780875d249019bd0cdf55eba960fb6f44be Mon Sep 17 00:00:00 2001 From: stuconnolly Date: Fri, 5 Nov 2010 21:15:18 +0000 Subject: Complete the implementation of supporting MySQL's XML schema format when exporting. Also, restore our old format and give the user the choice during export (defaults to MySQL schema). Completes the implementation of issue #840. --- Interfaces/English.lproj/ExportDialog.xib | 390 ++++++++++++++++++++++++++++-- Source/SPConstants.h | 7 + Source/SPExportController.h | 4 + Source/SPExportController.m | 17 ++ Source/SPExportFileUtilities.m | 11 +- Source/SPExportInitializer.m | 5 +- Source/SPXMLExporter.h | 28 ++- Source/SPXMLExporter.m | 313 +++++++++++++++--------- Source/SPXMLExporterDelegate.m | 21 +- 9 files changed, 662 insertions(+), 134 deletions(-) diff --git a/Interfaces/English.lproj/ExportDialog.xib b/Interfaces/English.lproj/ExportDialog.xib index 17f90795..1d2668e2 100644 --- a/Interfaces/English.lproj/ExportDialog.xib +++ b/Interfaces/English.lproj/ExportDialog.xib @@ -21,8 +21,7 @@ YES - - + YES @@ -55,7 +54,7 @@ {3.40282e+38, 3.40282e+38} {449, 480} - + 256 YES @@ -426,7 +425,6 @@ {451, 480} - {{0, 0}, {1680, 1028}} {449, 502} @@ -2311,14 +2309,14 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA xml - + 256 YES 268 - {{11, 200}, {72, 14}} + {{11, 112}, {72, 14}} YES @@ -2334,11 +2332,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{14, 173}, {55, 19}} + {{14, 85}, {55, 19}} YES - -1804468671 + -1267597759 272761856 @@ -2348,8 +2346,140 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA + + + 268 + {{11, 152}, {179, 18}} + + YES + + -2080244224 + 131072 + Structure + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{12, 176}, {180, 14}} + + YES + + 68288064 + 272761856 + Include: + + + + + + + + + 268 + {{11, 132}, {179, 18}} + + YES + + -2080244224 + 131072 + Content + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{59, 193}, {119, 22}} + + YES + + -2076049856 + 133120 + + + 109199615 + 129 + + + 400 + 75 + + + MySQL Schema + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + Plain Schema + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + + 1 + YES + YES + 2 + + + + + 268 + {{11, 198}, {46, 14}} + + YES + + 68288064 + 272761856 + Format: + + + + + + {{10, 7}, {189, 229}} + XML @@ -2358,10 +2488,9 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA pdf - + 256 {{10, 7}, {189, 229}} - PDF @@ -2379,14 +2508,14 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - + 4 YES YES YES - + @@ -3215,6 +3344,38 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 1350 + + + exportXMLIncludeContent + + + + 1363 + + + + exportXMLIncludeStructure + + + + 1364 + + + + exportXMLFormatPopUpButton + + + + 1373 + + + + toggleXMLOutputFormat: + + + + 1374 + @@ -4373,6 +4534,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES + + + + + @@ -4664,6 +4830,100 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA + + 1355 + + + YES + + + + + + 1356 + + + YES + + + + + + 1357 + + + YES + + + + + + 1358 + + + + + 1359 + + + + + 1360 + + + + + 1365 + + + YES + + + + + + 1366 + + + YES + + + + + + 1367 + + + YES + + + + + + + 1368 + + + + + 1369 + + + + + 1371 + + + YES + + + + + + 1372 + + + @@ -4745,10 +5005,13 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 1150.IBPluginDependency 1152.IBPluginDependency 1153.IBPluginDependency + 1153.IBViewBoundsToFrameTransform 1154.IBPluginDependency 1155.IBPluginDependency 1156.IBPluginDependency + 1156.IBViewBoundsToFrameTransform 1157.IBPluginDependency + 1157.IBViewBoundsToFrameTransform 1158.IBPluginDependency 1159.IBPluginDependency 1160.IBPluginDependency @@ -4863,6 +5126,25 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 1341.IBPluginDependency 1342.IBPluginDependency 1343.IBPluginDependency + 1355.IBPluginDependency + 1355.IBViewBoundsToFrameTransform + 1356.IBPluginDependency + 1356.IBViewBoundsToFrameTransform + 1357.IBPluginDependency + 1357.IBViewBoundsToFrameTransform + 1358.IBPluginDependency + 1359.IBPluginDependency + 1360.IBPluginDependency + 1365.IBPluginDependency + 1365.IBViewBoundsToFrameTransform + 1366.IBPluginDependency + 1367.IBEditorWindowLastContentRect + 1367.IBPluginDependency + 1368.IBPluginDependency + 1369.IBPluginDependency + 1371.IBPluginDependency + 1371.IBViewBoundsToFrameTransform + 1372.IBPluginDependency 2.IBPluginDependency 2.IBUserGuides 294.IBEditorWindowLastContentRect @@ -4936,7 +5218,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {449, 480} - {{226, 235}, {450, 359}} + {{463, 507}, {450, 359}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -5052,10 +5334,19 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBQAAAwywAAA + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBQAAAw1QAAA + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBMAAAw0AAAA + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -5219,6 +5510,35 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAADCeAAAwvQAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAADCdAAAww4AAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAADCdAAAwswAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCnAAAwxYAAA + + com.apple.InterfaceBuilder.CocoaPlugin + {{746, 640}, {140, 37}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABBMAAAwxIAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin YES @@ -5306,7 +5626,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - 1354 + 1374 @@ -5415,6 +5735,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA doSelectionUpperCase: doTranspose: insertNULLvalue: + moveSelectionLineDown: + moveSelectionLineUp: selectCurrentLine: selectCurrentWord: selectEnclosingBrackets: @@ -5434,6 +5756,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA id id id + id + id @@ -5450,6 +5774,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA doSelectionUpperCase: doTranspose: insertNULLvalue: + moveSelectionLineDown: + moveSelectionLineUp: selectCurrentLine: selectCurrentWord: selectEnclosingBrackets: @@ -5496,6 +5822,14 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA insertNULLvalue: id + + moveSelectionLineDown: + id + + + moveSelectionLineUp: + id + selectCurrentLine: id @@ -5557,6 +5891,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA toggleSQLIncludeContent: toggleSQLIncludeDropSyntax: toggleSQLIncludeStructure: + toggleXMLOutputFormat: YES @@ -5574,6 +5909,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA id id id + id @@ -5594,6 +5930,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA toggleSQLIncludeContent: toggleSQLIncludeDropSyntax: toggleSQLIncludeStructure: + toggleXMLOutputFormat: YES @@ -5653,6 +5990,10 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA toggleSQLIncludeStructure: id + + toggleXMLOutputFormat: + id + @@ -5704,6 +6045,9 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA exportTablelistScrollView exportTypeTabBar exportUseUTF8BOMButton + exportXMLFormatPopUpButton + exportXMLIncludeContent + exportXMLIncludeStructure exportXMLNULLValuesAsTextField exporterView tableContentInstance @@ -5758,6 +6102,9 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA NSScrollView NSTabView NSButton + NSPopUpButton + NSButton + NSButton NSTextField NSView id @@ -5815,6 +6162,9 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA exportTablelistScrollView exportTypeTabBar exportUseUTF8BOMButton + exportXMLFormatPopUpButton + exportXMLIncludeContent + exportXMLIncludeStructure exportXMLNULLValuesAsTextField exporterView tableContentInstance @@ -6004,6 +6354,18 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA exportUseUTF8BOMButton NSButton + + exportXMLFormatPopUpButton + NSPopUpButton + + + exportXMLIncludeContent + NSButton + + + exportXMLIncludeStructure + NSButton + exportXMLNULLValuesAsTextField NSTextField diff --git a/Source/SPConstants.h b/Source/SPConstants.h index a3665661..29207b89 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -83,6 +83,13 @@ enum { }; typedef NSUInteger SPSQLExportInsertDivider; +// XML export formats +enum { + SPXMLExportMySQLFormat = 0, + SPXMLExportPlainFormat = 1 +}; +typedef NSUInteger SPXMLExportFormat; + // Table row count query usage levels typedef enum { SPRowCountFetchNever = 0, diff --git a/Source/SPExportController.h b/Source/SPExportController.h index 32cf189a..24c30b39 100644 --- a/Source/SPExportController.h +++ b/Source/SPExportController.h @@ -104,6 +104,9 @@ IBOutlet NSTextField *exportCSVNULLValuesAsTextField; // XML + IBOutlet NSPopUpButton *exportXMLFormatPopUpButton; + IBOutlet NSButton *exportXMLIncludeStructure; + IBOutlet NSButton *exportXMLIncludeContent; IBOutlet NSTextField *exportXMLNULLValuesAsTextField; /** @@ -239,6 +242,7 @@ - (IBAction)toggleAdvancedExportOptionsView:(id)sender; - (IBAction)exportCustomQueryResultAsFormat:(id)sender; +- (IBAction)toggleXMLOutputFormat:(id)sender; - (IBAction)toggleSQLIncludeStructure:(id)sender; - (IBAction)toggleSQLIncludeContent:(id)sender; - (IBAction)toggleSQLIncludeDropSyntax:(id)sender; diff --git a/Source/SPExportController.m b/Source/SPExportController.m index 3ca2c996..755a4f74 100644 --- a/Source/SPExportController.m +++ b/Source/SPExportController.m @@ -492,6 +492,23 @@ static const NSString *SPTableViewDropColumnID = @"drop"; } } +/** + * Toggles the options available depending on the selected XML output format. + */ +- (IBAction)toggleXMLOutputFormat:(id)sender +{ + if ([sender indexOfSelectedItem] == SPXMLExportMySQLFormat) { + [exportXMLIncludeStructure setEnabled:YES]; + [exportXMLIncludeContent setEnabled:YES]; + [exportXMLNULLValuesAsTextField setEnabled:NO]; + } + else if ([sender indexOfSelectedItem] == SPXMLExportPlainFormat) { + [exportXMLIncludeStructure setEnabled:NO]; + [exportXMLIncludeContent setEnabled:NO]; + [exportXMLNULLValuesAsTextField setEnabled:YES]; + } +} + /** * Toggles the display of the advanced options box. */ diff --git a/Source/SPExportFileUtilities.m b/Source/SPExportFileUtilities.m index fd4be8b0..86631495 100644 --- a/Source/SPExportFileUtilities.m +++ b/Source/SPExportFileUtilities.m @@ -86,13 +86,16 @@ [header appendFormat:@"- %@: %@\n", NSLocalizedString(@"Database", @"export header database label"), [tableDocumentInstance database]]; [header appendFormat:@"- %@ Time: %@\n", NSLocalizedString(@"Generation Time", @"export header generation time label"), [NSDate date]]; [header appendString:@"-\n-->\n\n"]; - [header appendFormat:@"<%@ xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n", (exportSource == SPTableExport) ? @"mysqldump" : @"resultset"]; - if (exportSource == SPTableExport) { - [header appendFormat:@"\n\n", [tableDocumentInstance database]]; + if ([exportXMLFormatPopUpButton indexOfSelectedItem] == SPXMLExportMySQLFormat) { + [header appendFormat:@"<%@ xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n", (exportSource == SPTableExport) ? @"mysqldump" : @"resultset"]; + + if (exportSource == SPTableExport) { + [header appendFormat:@"\n\n", [tableDocumentInstance database]]; + } } else { - [header appendString:@"\n"]; + [header appendFormat:@"<%@>\n\n", [[tableDocumentInstance database] HTMLEscapeString]]; } [file writeData:[header dataUsingEncoding:NSUTF8StringEncoding]]; diff --git a/Source/SPExportInitializer.m b/Source/SPExportInitializer.m index 7b1b9451..9544bf4b 100644 --- a/Source/SPExportInitializer.m +++ b/Source/SPExportInitializer.m @@ -503,7 +503,10 @@ // Regardless of the export source, set exporter's table name as it's used in the output // of table and table content exports. [xmlExporter setXmlTableName:table]; - + + [xmlExporter setXmlFormat:[exportXMLFormatPopUpButton indexOfSelectedItem]]; + [xmlExporter setXmlOutputIncludeStructure:[exportXMLIncludeStructure state]]; + [xmlExporter setXmlOutputIncludeContent:[exportXMLIncludeContent state]]; [xmlExporter setXmlNULLString:[exportXMLNULLValuesAsTextField stringValue]]; // If required create separate files diff --git a/Source/SPXMLExporter.h b/Source/SPXMLExporter.h index 8d7a740c..f7b94f86 100644 --- a/Source/SPXMLExporter.h +++ b/Source/SPXMLExporter.h @@ -41,27 +41,47 @@ NSString *xmlTableName; NSString *xmlNULLString; + + BOOL xmlOutputIncludeStructure; + BOOL xmlOutputIncludeContent; + + SPXMLExportFormat xmlFormat; } /** * @property delegate Exporter delegate */ -@property(readwrite, assign) NSObject *delegate; +@property (readwrite, assign) NSObject *delegate; /** * @property xmlDataArray Data array */ -@property(readwrite, retain) NSArray *xmlDataArray; +@property (readwrite, retain) NSArray *xmlDataArray; /** * @property xmlTableName Table name */ -@property(readwrite, retain) NSString *xmlTableName; +@property (readwrite, retain) NSString *xmlTableName; /** * @property xmlNULLString XML NULL string */ -@property(readwrite, retain) NSString *xmlNULLString; +@property (readwrite, retain) NSString *xmlNULLString; + +/** + * @property xmlOutputIncludeStructure Include table structure + */ +@property (readwrite, assign) BOOL xmlOutputIncludeStructure; + +/** + * @property xmlOutputIncludeContent Include table content + */ +@property (readwrite, assign) BOOL xmlOutputIncludeContent; + +/** + * @property xmlFormat + */ +@property (readwrite, assign) SPXMLExportFormat xmlFormat; - (id)initWithDelegate:(NSObject *)exportDelegate; diff --git a/Source/SPXMLExporter.m b/Source/SPXMLExporter.m index 1ff32018..962d5a53 100644 --- a/Source/SPXMLExporter.m +++ b/Source/SPXMLExporter.m @@ -35,6 +35,9 @@ @synthesize xmlDataArray; @synthesize xmlTableName; @synthesize xmlNULLString; +@synthesize xmlOutputIncludeStructure; +@synthesize xmlOutputIncludeContent; +@synthesize xmlFormat; /** * Initialise an instance of SPXMLExporter using the supplied delegate. @@ -62,13 +65,20 @@ { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + BOOL isTableExport = NO; + NSArray *xmlRow = nil; NSArray *fieldNames = nil; NSString *dataConversionString = nil; + + // Result sets + MCPResult *statusResult = nil; + MCPResult *structureResult = nil; MCPStreamingResult *streamingResult = nil; + NSMutableArray *xmlTags = [NSMutableArray array]; NSMutableString *xmlString = [NSMutableString string]; - NSMutableString *xmlItem = [NSMutableString string]; + NSMutableString *xmlItem = [NSMutableString string]; NSUInteger xmlRowCount = 0; NSUInteger i, totalRows, currentRowIndex, lastProgressValue, currentPoolDataLength; @@ -76,7 +86,8 @@ // Check to see if we have at least a table name or data array if ((![self xmlTableName]) && (![self xmlDataArray]) || ([[self xmlTableName] length] == 0) && ([[self xmlDataArray] count] == 0) || - (![self xmlNULLString])) + (([self xmlFormat] == SPXMLExportMySQLFormat) && ((![self xmlOutputIncludeStructure]) && (![self xmlOutputIncludeContent]))) || + (([self xmlFormat] == SPXMLExportPlainFormat) && (![self xmlNULLString]))) { [pool release]; return; @@ -92,67 +103,105 @@ // 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]; + + isTableExport = YES; + + 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]]; - [xmlString appendFormat:@"\t\n\n", [self xmlTableName]]; + // Only include the structure if necessary + if (([self xmlFormat] == SPXMLExportMySQLFormat) && [self xmlOutputIncludeStructure]) { + + structureResult = [connection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [[self xmlTableName] backtickQuotedString]]]; + statusResult = [connection queryString:[NSString stringWithFormat:@"SHOW TABLE STATUS LIKE %@", [[self xmlTableName] tickQuotedString]]]; + + if ([structureResult numOfRows] && [statusResult numOfRows]) { + + [statusResult dataSeek:0]; + [structureResult dataSeek:0]; + + [xmlString appendFormat:@"\t\n", [self xmlTableName]]; + + for (i = 0; i < [structureResult numOfRows]; i++) + { + NSDictionary *row = [structureResult fetchRowAsDictionary]; + + [xmlString appendFormat:@"\t\t\n", + [row objectForKey:@"Field"], + [row objectForKey:@"Type"], + [row objectForKey:@"Null"], + [row objectForKey:@"Key"], + [row objectForKey:@"Default"], + [row objectForKey:@"Extra"]]; + } + + NSDictionary *row = [statusResult fetchRowAsDictionary]; + + [xmlString appendFormat:@"\n\t\t\n", + [row objectForKey:@"Name"], + [row objectForKey:@"Engine"], + [row objectForKey:@"Version"], + [row objectForKey:@"Row_format"], + [row objectForKey:@"Rows"], + [row objectForKey:@"Avg_row_length"], + [row objectForKey:@"Data_length"], + [row objectForKey:@"Max_data_length"], + [row objectForKey:@"Index_length"], + [row objectForKey:@"Data_free"], + [row objectForKey:@"Create_time"], + [row objectForKey:@"Update_time"], + [row objectForKey:@"Collation"], + [row objectForKey:@"Create_options"], + [row objectForKey:@"Comment"]]; + + [xmlString appendFormat:@"\t\n\n"]; + } + } + + if (([self xmlFormat] == SPXMLExportMySQLFormat) && [self xmlOutputIncludeContent]) { + [xmlString appendFormat:@"\t\n\n", [self xmlTableName]]; + } + + [[self exportOutputFile] writeData:[xmlString dataUsingEncoding:[self exportOutputEncoding]]]; } else { totalRows = [[self xmlDataArray] count]; } - // Set up an array of encoded field names as opening and closing tags - fieldNames = ([self xmlDataArray]) ? [[self xmlDataArray] objectAtIndex:0] : [streamingResult fetchFieldNames]; + // Only proceed to export the content if this is not a table export or it is and include content is selected + if ((!isTableExport) || (isTableExport && [self xmlOutputIncludeContent])) { - [[self exportOutputFile] writeData:[xmlString 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; - - // Inform the delegate that we are about to start writing the data to disk - [delegate performSelectorOnMainThread:@selector(xmlExportProcessWillBeginWritingData:) withObject:self waitUntilDone:NO]; - - while (1) - { - // Check for cancellation flag - if ([self isCancelled]) { - if (streamingResult) { - [connection cancelCurrentQuery]; - [streamingResult cancelResultLoad]; - } - - [xmlExportPool release]; - [pool release]; + // Set up an array of encoded field names as opening and closing tags + fieldNames = ([self xmlDataArray]) ? NSArrayObjectAtIndex([self xmlDataArray], 0) : [streamingResult fetchFieldNames]; + + for (i = 0; i < [fieldNames count]; i++) + { + [xmlTags addObject:[NSMutableArray array]]; - return; + [NSArrayObjectAtIndex(xmlTags, i) addObject:[NSString stringWithFormat:@"\t\t<%@>", [[NSArrayObjectAtIndex(fieldNames, i) description] HTMLEscapeString]]]; + [NSArrayObjectAtIndex(xmlTags, i) addObject:[NSString stringWithFormat:@"\n", [[NSArrayObjectAtIndex(fieldNames, i) description] HTMLEscapeString]]]; } - // 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; + // If required, write an opening tag in the form of the table name + if ([self xmlFormat] == SPXMLExportPlainFormat) { + [[self exportOutputFile] 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; + + if ([self xmlDataArray]) currentRowIndex++; + + // Drop into the processing loop + NSAutoreleasePool *xmlExportPool = [[NSAutoreleasePool alloc] init]; + + currentPoolDataLength = 0; - // Construct the row - [xmlString setString:@"\t\n"]; + // Inform the delegate that we are about to start writing the data to disk + [delegate performSelectorOnMainThread:@selector(xmlExportProcessWillBeginWritingData:) withObject:self waitUntilDone:NO]; - for (i = 0; i < xmlRowCount; i++) + while (1) { // Check for cancellation flag if ([self isCancelled]) { @@ -167,76 +216,126 @@ return; } - BOOL dataIsNULL = NO; - id data = NSArrayObjectAtIndex(xmlRow, i); + // 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; + } - // Retrieve the contents of this tag - if ([data isKindOfClass:[NSData class]]) { - dataConversionString = [[NSString alloc] initWithData:data encoding:[self exportOutputEncoding]]; + // Get the cell count if we don't already have it stored + if (!xmlRowCount) xmlRowCount = [xmlRow count]; + + // Construct the row + [xmlString setString:@"\t\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; + } - if (dataConversionString == nil) { - dataConversionString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + BOOL dataIsNULL = NO; + id data = NSArrayObjectAtIndex(xmlRow, i); + + // Retrieve the contents of this tag + if ([data isKindOfClass:[NSData class]]) { + dataConversionString = [[NSString alloc] initWithData:data encoding:[self exportOutputEncoding]]; + + if (dataConversionString == nil) { + dataConversionString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + } + + [xmlItem setString:[NSString stringWithString:dataConversionString]]; + [dataConversionString release]; + } + else if ([data isKindOfClass:[NSNull class]]) { + dataIsNULL = YES; + + if ([self xmlFormat] == SPXMLExportPlainFormat) { + [xmlItem setString:[self xmlNULLString]]; + } + } + else if ([data isKindOfClass:[MCPGeometryData class]]) { + [xmlItem setString:[data wktString]]; + } + else { + [xmlItem setString:[data description]]; } - [xmlItem setString:[NSString stringWithString:dataConversionString]]; - [dataConversionString release]; - } - else if ([data isKindOfClass:[NSNull class]]) { - dataIsNULL = YES; - } - else if ([data isKindOfClass:[MCPGeometryData class]]) { - [xmlItem setString:[data wktString]]; - } - else { - [xmlItem setString:[data description]]; + if ([self xmlFormat] == SPXMLExportMySQLFormat) { + [xmlString appendFormat:@"\t\t\n"]; + } + else { + [xmlString appendFormat:@">%@\n", [xmlItem HTMLEscapeString]]; + } + } + else if ([self xmlFormat] == SPXMLExportPlainFormat) { + // 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 appendFormat:@"\t\t\n"]; - } - else { - [xmlString appendFormat:@">%@\n", [xmlItem HTMLEscapeString]]; - } - } - - [xmlString appendString:@"\t\n\n"]; + [xmlString appendString:@"\t\n\n"]; + + // Record the total length for use with pool flushing + currentPoolDataLength += [xmlString length]; + + // Write the row to the filehandle + [[self exportOutputFile] writeData:[xmlString dataUsingEncoding:[self exportOutputEncoding]]]; + + // Update the progress counter and progress bar + currentRowIndex++; + + // Update the progress + if (totalRows && (currentRowIndex * ([self exportMaxProgress] / totalRows)) > lastProgressValue) { - // Record the total length for use with pool flushing - currentPoolDataLength += [xmlString length]; - - // Write the row to the filehandle - [[self exportOutputFile] 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; + } - NSInteger progress = (currentRowIndex * ([self exportMaxProgress] / totalRows)); + // Inform the delegate that the export's progress has been updated + [delegate performSelectorOnMainThread:@selector(xmlExportProcessProgressUpdated:) withObject:self waitUntilDone:NO]; - [self setExportProgressValue:progress]; - - lastProgressValue = progress; + // 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; } - // 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 (([self xmlFormat] == SPXMLExportMySQLFormat) && isTableExport) { + [[self exportOutputFile] writeData:[@"\t\n\n" dataUsingEncoding:[self exportOutputEncoding]]]; + } + else if ([self xmlFormat] == SPXMLExportPlainFormat) { + [[self exportOutputFile] writeData:[[NSString stringWithFormat:@"\t\n\n", ([self xmlTableName]) ? [[self xmlTableName] HTMLEscapeString] : @"custom"] dataUsingEncoding:[self exportOutputEncoding]]]; } - // If an array was supplied and we've processed all rows, break - if ([self xmlDataArray] && totalRows == currentRowIndex) break; - } - - if ((![self xmlDataArray]) && [self xmlTableName]) { - [[self exportOutputFile] writeData:[@"\t\n\n" dataUsingEncoding:[self exportOutputEncoding]]]; + [xmlExportPool release]; } // Write data to disk @@ -248,7 +347,6 @@ // Inform the delegate that the export process is complete [delegate performSelectorOnMainThread:@selector(xmlExportProcessComplete:) withObject:self waitUntilDone:NO]; - [xmlExportPool release]; [pool release]; } @@ -259,8 +357,7 @@ { if (xmlDataArray) [xmlDataArray release], xmlDataArray = nil; if (xmlTableName) [xmlTableName release], xmlTableName = nil; - - [xmlNULLString release], xmlNULLString = nil; + if (xmlNULLString) [xmlNULLString release], xmlNULLString = nil; [super dealloc]; } diff --git a/Source/SPXMLExporterDelegate.m b/Source/SPXMLExporterDelegate.m index cae852ac..9d8b97cf 100644 --- a/Source/SPXMLExporterDelegate.m +++ b/Source/SPXMLExporterDelegate.m @@ -69,8 +69,16 @@ // If we're exporting to multiple files then close the file handle of the exporter // that just finished, ensuring its data is written to disk. if (exportToMultipleFiles) { - [[exporter exportOutputFile] writeData:[(exportSource == SPTableExport) ? @"\n\n" : @"\n" dataUsingEncoding:[connection stringEncoding]]]; + NSString *string = @""; + if ([exporter xmlFormat] == SPXMLExportMySQLFormat) { + string = (exportSource == SPTableExport) ? @"\n\n" : @"\n";; + } + else if ([exporter xmlFormat] == SPXMLExportPlainFormat) { + string = [NSString stringWithFormat:@"\n", [[tableDocumentInstance database] HTMLEscapeString]]; + } + + [[exporter exportOutputFile] writeData:[string dataUsingEncoding:[connection stringEncoding]]]; [[exporter exportOutputFile] close]; } @@ -82,9 +90,16 @@ } // Otherwise if the exporter list is empty, close the progress sheet else { - [[exporter exportOutputFile] writeData:[(exportSource == SPTableExport) ? @"\n\n" : @"\n" dataUsingEncoding:[connection stringEncoding]]]; + NSString *string = @""; + + if ([exporter xmlFormat] == SPXMLExportMySQLFormat) { + string = (exportSource == SPTableExport) ? @"\n\n" : @"\n";; + } + else if ([exporter xmlFormat] == SPXMLExportPlainFormat) { + string = [NSString stringWithFormat:@"\n", [[tableDocumentInstance database] HTMLEscapeString]]; + } - // Close the last exporter's file handle + [[exporter exportOutputFile] writeData:[string dataUsingEncoding:[connection stringEncoding]]]; [[exporter exportOutputFile] close]; [NSApp endSheet:exportProgressWindow returnCode:0]; -- cgit v1.2.3