[PATCH] Export dives to UDDF file
Dirk Hohndel
dirk at hohndel.org
Sat Mar 23 09:51:33 PDT 2013
You could try one of the free online dive logs like divelogs.de to test...
/D
On March 23, 2013 9:19:59 AM Miika Turkia <miika.turkia at gmail.com> wrote:
> 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 at gmail.com>
> ---
> I would appreciate if someone with a divelog that supports UDDF import
> would give this a test. I have tried it with Subsurface but obviously
> there is quite a bit of data discarded on export-import cycle. This is
> hopefully mainly due to import missing features, but could be the export
> as well...
> ---
> divelist.c | 95 +++++++++++++++++++++++++
> divelist.h | 1 +
> gtk-gui.c | 2 +
> xslt/uddf-export.xslt | 186 +++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 284 insertions(+)
> create mode 100644 xslt/uddf-export.xslt
>
> diff --git a/divelist.c b/divelist.c
> index c25ee62..198e2d6 100644
> --- a/divelist.c
> +++ b/divelist.c
> @@ -2102,6 +2102,92 @@ static void export_selected_dives_cb(GtkWidget
> *menuitem, GtkTreePath *path)
> }
> #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)
> {
> 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 deletesinglelabel[] = N_("Delete dive");
> char *deletelabel;
> +#if defined(XSLT)
> + char exportuddflabel[] = N_("Export dive(s) to UDDF");
> +#endif
> #if defined(LIBZIP) && defined(XSLT)
> char exportlabel[] = N_("Export dive(s)");
> #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);
> #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);
> g_signal_connect(menuitem, "activate",
> G_CALLBACK(edit_selected_dives_cb), NULL);
> gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
> diff --git a/divelist.h b/divelist.h
> index 47f79e2..856318e 100644
> --- a/divelist.h
> +++ b/divelist.h
> @@ -15,4 +15,5 @@ extern void select_next_dive(void);
> extern void select_prev_dive(void);
> extern void show_and_select_dive(struct dive *dive);
> extern double init_decompression(struct dive * dive);
> +extern void export_all_dives_uddf_cb();
> #endif
> diff --git a/gtk-gui.c b/gtk-gui.c
> index c5b9a80..82e9a31 100644
> --- a/gtk-gui.c
> +++ b/gtk-gui.c
> @@ -1509,6 +1509,7 @@ static GtkActionEntry menu_items[] = {
> { "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) },
> { "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) },
> { "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) },
> @@ -1550,6 +1551,7 @@ static const gchar* ui_string = " \
> <menuitem name=\"Close\" action=\"CloseFile\" /> \
> <separator name=\"Separator1\"/> \
> <menuitem name=\"Import XML File\" action=\"ImportFile\" /> \
> + <menuitem name=\"Export to UDDF File\" action=\"ExportUDDF\" /> \
> <separator name=\"Separator2\"/> \
> <menuitem name=\"Print\" action=\"Print\" /> \
> <separator name=\"Separator3\"/> \
> diff --git a/xslt/uddf-export.xslt b/xslt/uddf-export.xslt
> new file mode 100644
> index 0000000..1097990
> --- /dev/null
> +++ b/xslt/uddf-export.xslt
> @@ -0,0 +1,186 @@
> +<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 xmlns="http://www.streit.cc/uddf/3.2/" version="3.2.0">
> + <generator>
> + <manufacturer id="subsurface">
> + <name>Subsurface Team</name>
> + <contact>http://subsurface.hohndel.org/</contact>
> + </manufacturer>
> + <version>
> + <xsl:value-of select="subsurfaceversion"/>
> + </version>
> + <datetime>
> + <xsl:if test="/divelog/generator/@date != ''">
> + <xsl:value-of select="concat(/divelog/generator/@date,
> 'T', /divelog/generator/@time)"/>
> + </xsl:if>
> + </datetime>
> + </generator>
> +
> + <diver>
> + <xsl:variable name="owner">
> + <xsl:choose>
> + <xsl:when test="/divelog/owner != ''">
> + <xsl:value-of select="generate-id(/divelog/owner)"/>
> + </xsl:when>
> + <xsl:otherwise>
> + <xsl:value-of select="'owner'"/>
> + </xsl:otherwise>
> + </xsl:choose>
> + </xsl:variable>
> + <owner id="{$owner}">
> + <personal>
> + <firstname>
> + <xsl:value-of select="/divelog/owner/@firstname"/>
> + </firstname>
> + <lastname>
> + <xsl:value-of select="/divelog/owner/@lastname"/>
> + </lastname>
> + </personal>
> + <equipment>
> + <xsl:for-each select="/divelog/settings/divecomputerid">
> + <divecomputer id="{./@deviceid}">
> + <name>
> + <xsl:value-of select="./@model"/>
> + </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 xmlns="http://www.streit.cc/uddf/3.2/" id="{generate-id(.)}">
> +
> + <informationbeforedive>
> + <airtemperature>
> + <xsl:value-of
> select="format-number(substring-before(node()/temperature/@air, ' ') +
> 273.15, '0.00')"/>
> + </airtemperature>
> + <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>
> + <tankvolume>
> + <xsl:value-of select="substring-before(./cylinder[1]/@size, ' ')"/>
> + </tankvolume>
> + <tankpressurebegin>
> + <xsl:value-of select="substring-before(./cylinder[1]/@start, ' ')"/>
> + </tankpressurebegin>
> + <tankpressureend>
> + <xsl:value-of select="substring-before(./cylinder[1]/@end, ' ')"/>
> + </tankpressureend>
> + </tankdata>
> +
> + <informationafterdive>
> + <greatestdepth>
> + <xsl:value-of select="substring-before(node()/depth/@max, ' ')"/>
> + </greatestdepth>
> + <averagedepth>
> + <xsl:value-of select="substring-before(node()/depth/@mean, ' ')"/>
> + </averagedepth>
> + <diveduration>
> + <xsl:call-template name="time2sec">
> + <xsl:with-param name="time">
> + <xsl:value-of select="./@duration"/>
> + </xsl:with-param>
> + </xsl:call-template>
> + </diveduration>
> + <lowesttemperature>
> + <xsl:value-of
> select="format-number(substring-before(node()/temperature/@water, ' ')
> + 273.15, '0.00')"/>
> + </lowesttemperature>
> + <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>
> --
> 1.7.9.5
>
> _______________________________________________
> subsurface mailing list
> subsurface at hohndel.org
> http://lists.hohndel.org/cgi-bin/mailman/listinfo/subsurface
More information about the subsurface
mailing list