Export dives to UDDF file

This patch implements exporting dives from Subsurface to UDDF format.
Events and cylinder info are the most remarkable things still missing
from the export.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Miika Turkia 2013-03-24 10:00:25 +02:00 committed by Dirk Hohndel
parent ca0ecc234a
commit 12d5ab4ce3
4 changed files with 289 additions and 0 deletions

View file

@ -2102,6 +2102,92 @@ static void export_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path)
} }
#endif #endif
#if defined(XSLT)
static void export_dives_uddf(const gboolean selected)
{
FILE *f;
char *filename = NULL;
size_t streamsize;
char *membuf;
xmlDoc *doc;
xsltStylesheetPtr xslt = NULL;
xmlDoc *transformed;
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new(_("Export As UDDF File"),
GTK_WINDOW(main_window),
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
}
gtk_widget_destroy(dialog);
if (!filename)
return;
/* Save XML to file and convert it into a memory buffer */
save_dives_logic(filename, selected);
f = fopen(filename, "r");
fseek(f, 0, SEEK_END);
streamsize = ftell(f);
rewind(f);
membuf = malloc(streamsize + 1);
if (!membuf || !fread(membuf, streamsize, 1, f)) {
fprintf(stderr, "Failed to read memory buffer\n");
return;
}
membuf[streamsize] = 0;
fclose(f);
g_unlink(filename);
/*
* Parse the memory buffer into XML document and
* transform it to UDDF format, finally dumping
* the XML into a character buffer.
*/
doc = xmlReadMemory(membuf, strlen(membuf), "divelog", NULL, 0);
if (!doc) {
fprintf(stderr, "Failed to read XML memory\n");
return;
}
free((void *)membuf);
/* Convert to UDDF format */
xslt = get_stylesheet("uddf-export.xslt");
if (!xslt) {
fprintf(stderr, "Failed to open UDDF conversion stylesheet\n");
return;
}
transformed = xsltApplyStylesheet(xslt, doc, NULL);
xsltFreeStylesheet(xslt);
xmlFreeDoc(doc);
/* Write the transformed XML to file */
f = g_fopen(filename, "w");
xmlDocFormatDump(f, transformed, 1);
xmlFreeDoc(transformed);
fclose(f);
g_free(filename);
}
static void export_selected_dives_uddf_cb(GtkWidget *menuitem, GtkTreePath *path)
{
export_dives_uddf(TRUE);
}
void export_all_dives_uddf_cb()
{
export_dives_uddf(FALSE);
}
#endif
static void merge_dive_index(int i, struct dive *a) static void merge_dive_index(int i, struct dive *a)
{ {
struct dive *b = get_dive(i+1); struct dive *b = get_dive(i+1);
@ -2171,6 +2257,9 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
char deleteplurallabel[] = N_("Delete dives"); char deleteplurallabel[] = N_("Delete dives");
char deletesinglelabel[] = N_("Delete dive"); char deletesinglelabel[] = N_("Delete dive");
char *deletelabel; char *deletelabel;
#if defined(XSLT)
char exportuddflabel[] = N_("Export dive(s) to UDDF");
#endif
#if defined(LIBZIP) && defined(XSLT) #if defined(LIBZIP) && defined(XSLT)
char exportlabel[] = N_("Export dive(s)"); char exportlabel[] = N_("Export dive(s)");
#endif #endif
@ -2247,6 +2336,12 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
#endif #endif
#if defined(XSLT)
menuitem = gtk_menu_item_new_with_label(exportuddflabel);
g_signal_connect(menuitem, "activate", G_CALLBACK(export_selected_dives_uddf_cb), path);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
#endif
menuitem = gtk_menu_item_new_with_label(editlabel); menuitem = gtk_menu_item_new_with_label(editlabel);
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL); g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);

View file

@ -15,4 +15,5 @@ extern void select_next_dive(void);
extern void select_prev_dive(void); extern void select_prev_dive(void);
extern void show_and_select_dive(struct dive *dive); extern void show_and_select_dive(struct dive *dive);
extern double init_decompression(struct dive * dive); extern double init_decompression(struct dive * dive);
extern void export_all_dives_uddf_cb();
#endif #endif

View file

@ -1509,6 +1509,7 @@ static GtkActionEntry menu_items[] = {
{ "CloseFile", GTK_STOCK_CLOSE, N_("Close"), NULL, NULL, G_CALLBACK(file_close) }, { "CloseFile", GTK_STOCK_CLOSE, N_("Close"), NULL, NULL, G_CALLBACK(file_close) },
{ "Print", GTK_STOCK_PRINT, N_("Print..."), CTRLCHAR "P", NULL, G_CALLBACK(do_print) }, { "Print", GTK_STOCK_PRINT, N_("Print..."), CTRLCHAR "P", NULL, G_CALLBACK(do_print) },
{ "ImportFile", NULL, N_("Import File(s)..."), CTRLCHAR "I", NULL, G_CALLBACK(import_files) }, { "ImportFile", NULL, N_("Import File(s)..."), CTRLCHAR "I", NULL, G_CALLBACK(import_files) },
{ "ExportUDDF", NULL, N_("Export UDDF..."), NULL, NULL, G_CALLBACK(export_all_dives_uddf_cb) },
{ "DownloadLog", NULL, N_("Download From Dive Computer..."), CTRLCHAR "D", NULL, G_CALLBACK(download_dialog) }, { "DownloadLog", NULL, N_("Download From Dive Computer..."), CTRLCHAR "D", NULL, G_CALLBACK(download_dialog) },
{ "DownloadWeb", GTK_STOCK_CONNECT, N_("Download From Web Service..."), NULL, NULL, G_CALLBACK(webservice_download_dialog) }, { "DownloadWeb", GTK_STOCK_CONNECT, N_("Download From Web Service..."), NULL, NULL, G_CALLBACK(webservice_download_dialog) },
{ "AddDive", GTK_STOCK_ADD, N_("Add Dive..."), NULL, NULL, G_CALLBACK(add_dive_cb) }, { "AddDive", GTK_STOCK_ADD, N_("Add Dive..."), NULL, NULL, G_CALLBACK(add_dive_cb) },
@ -1550,6 +1551,7 @@ static const gchar* ui_string = " \
<menuitem name=\"Close\" action=\"CloseFile\" /> \ <menuitem name=\"Close\" action=\"CloseFile\" /> \
<separator name=\"Separator1\"/> \ <separator name=\"Separator1\"/> \
<menuitem name=\"Import XML File\" action=\"ImportFile\" /> \ <menuitem name=\"Import XML File\" action=\"ImportFile\" /> \
<menuitem name=\"Export to UDDF File\" action=\"ExportUDDF\" /> \
<separator name=\"Separator2\"/> \ <separator name=\"Separator2\"/> \
<menuitem name=\"Print\" action=\"Print\" /> \ <menuitem name=\"Print\" action=\"Print\" /> \
<separator name=\"Separator3\"/> \ <separator name=\"Separator3\"/> \

191
xslt/uddf-export.xslt Normal file
View file

@ -0,0 +1,191 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:import href="commonTemplates.xsl"/>
<xsl:strip-space elements="*"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="/divelog/dives">
<uddf version="3.2.0">
<generator>
<manufacturer id="subsurface">
<name>Subsurface Team</name>
<contact>http://subsurface.hohndel.org/</contact>
</manufacturer>
<version>
<xsl:value-of select="/divelog/@version"/>
</version>
<xsl:if test="/divelog/generator/@date != ''">
<datetime>
<xsl:value-of select="concat(/divelog/generator/@date, 'T', /divelog/generator/@time)"/>
</datetime>
</xsl:if>
</generator>
<diver>
<owner id="1">
<equipment>
<xsl:for-each select="/divelog/settings/divecomputerid">
<divecomputer id="{./@deviceid}">
<name>
<xsl:choose>
<xsl:when test="./@nickname != ''">
<xsl:value-of select="./@nickname"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="./@model"/>
</xsl:otherwise>
</xsl:choose>
</name>
<model>
<xsl:value-of select="./@model"/>
</model>
</divecomputer>
</xsl:for-each>
</equipment>
</owner>
</diver>
<!-- Gas definitions is not yet working, so it is commented out
-->
<xsl:if test="'asdf' = ''">
<gasdefinitions>
<xsl:for-each select="dive/cylinder">
<mix id="{generate-id(.)}">
<name>
<xsl:value-of select="concat(./@o2, '/', ./he)"/>
</name>
<o2>
<xsl:value-of select="./@o2"/>
</o2>
<he>
<xsl:value-of select="./@he"/>
</he>
</mix>
</xsl:for-each>
</gasdefinitions>
</xsl:if>
<profiledata>
<xsl:for-each select="trip">
<repetitiongroup id="{generate-id(.)}">
<xsl:apply-templates select="dive"/>
</repetitiongroup>
</xsl:for-each>
<xsl:for-each select="dive">
<repetitiongroup id="{generate-id(.)}">
<xsl:apply-templates select="."/>
</repetitiongroup>
</xsl:for-each>
</profiledata>
</uddf>
</xsl:template>
<xsl:template match="dive">
<dive id="{generate-id(.)}">
<informationbeforedive>
<xsl:if test="node()/temperature/@air != ''">
<airtemperature>
<xsl:value-of select="format-number(substring-before(node()/temperature/@air, ' ') + 273.15, '0.00')"/>
</airtemperature>
</xsl:if>
<datetime>
<xsl:value-of select="concat(./@date, 'T', ./@time)"/>
</datetime>
<divenumber>
<xsl:value-of select="./@number"/>
</divenumber>
</informationbeforedive>
<samples>
<xsl:for-each select="./divecomputer[1]/sample">
<waypoint>
<depth>
<xsl:value-of select="substring-before(./@depth, ' ')"/>
</depth>
<divetime>
<xsl:call-template name="time2sec">
<xsl:with-param name="time">
<xsl:value-of select="./@time"/>
</xsl:with-param>
</xsl:call-template>
</divetime>
<xsl:if test="./@pressure != ''">
<tankpressure>
<xsl:value-of select="substring-before(./@pressure, ' ')"/>
</tankpressure>
</xsl:if>
<xsl:if test="./@temp != ''">
<temperature>
<xsl:value-of select="format-number(substring-before(./@temp, ' ') + 273.15, '0.00')"/>
</temperature>
</xsl:if>
</waypoint>
</xsl:for-each>
</samples>
<tankdata>
<xsl:if test="./cylinder[1]/@size">
<tankvolume>
<xsl:value-of select="substring-before(./cylinder[1]/@size, ' ')"/>
</tankvolume>
</xsl:if>
<xsl:if test="./cylinder[1]/@start">
<tankpressurebegin>
<xsl:value-of select="substring-before(./cylinder[1]/@start, ' ')"/>
</tankpressurebegin>
</xsl:if>
<xsl:if test="./cylinder[1]/@end">
<tankpressureend>
<xsl:value-of select="substring-before(./cylinder[1]/@end, ' ')"/>
</tankpressureend>
</xsl:if>
</tankdata>
<informationafterdive>
<xsl:if test="node()/depth/@max != ''">
<greatestdepth>
<xsl:value-of select="substring-before(node()/depth/@max, ' ')"/>
</greatestdepth>
</xsl:if>
<xsl:if test="node()/depth/@mean != ''">
<averagedepth>
<xsl:value-of select="substring-before(node()/depth/@mean, ' ')"/>
</averagedepth>
</xsl:if>
<xsl:if test="./@duration != ''">
<diveduration>
<xsl:call-template name="time2sec">
<xsl:with-param name="time">
<xsl:value-of select="./@duration"/>
</xsl:with-param>
</xsl:call-template>
</diveduration>
</xsl:if>
<xsl:if test="node()/temperature/@water != ''">
<lowesttemperature>
<xsl:value-of select="format-number(substring-before(node()/temperature/@water, ' ') + 273.15, '0.00')"/>
</lowesttemperature>
</xsl:if>
<notes>
<para>
<xsl:value-of select="notes"/>
</para>
</notes>
<rating>
<ratingvalue>
<xsl:choose>
<xsl:when test="./@rating = 0">
<xsl:value-of select="'1'"/>
</xsl:when>
<xsl:when test="./@rating != ''">
<xsl:value-of select="./@rating * 2"/>
</xsl:when>
</xsl:choose>
</ratingvalue>
</rating>
</informationafterdive>
</dive>
</xsl:template>
</xsl:stylesheet>