[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