diff options
-rw-r--r-- | core/dive.h | 1 | ||||
-rw-r--r-- | core/file.c | 14 | ||||
-rw-r--r-- | core/qthelper.cpp | 133 | ||||
-rw-r--r-- | core/qthelper.h | 2 | ||||
-rw-r--r-- | core/qthelperfromc.h | 1 | ||||
-rw-r--r-- | desktop-widgets/divelogimportdialog.cpp | 61 | ||||
-rw-r--r-- | dives/TestDiveSeabearNewFormat.xml | 36 | ||||
-rw-r--r-- | tests/testparse.cpp | 120 | ||||
-rw-r--r-- | xslt/csv2xml.xslt | 25 |
9 files changed, 199 insertions, 194 deletions
diff --git a/core/dive.h b/core/dive.h index fa6133bd3..4402788c2 100644 --- a/core/dive.h +++ b/core/dive.h @@ -704,6 +704,7 @@ extern int parse_dlf_buffer(unsigned char *buffer, size_t size); extern int parse_file(const char *filename); extern int parse_csv_file(const char *filename, char **params, int pnr, const char *csvtemplate); +extern int parse_seabear_log(const char *filename); extern int parse_seabear_csv_file(const char *filename, char **params, int pnr, const char *csvtemplate); extern int parse_txt_file(const char *filename, const char *csv); extern int parse_manual_file(const char *filename, char **params, int pnr); diff --git a/core/file.c b/core/file.c index 59d00badb..7b24da8e7 100644 --- a/core/file.c +++ b/core/file.c @@ -1056,6 +1056,20 @@ int parse_csv_file(const char *filename, char **params, int pnr, const char *csv } #define SBPARAMS 40 +int parse_seabear_log(const char *filename) +{ + char *params[SBPARAMS]; + int pnr = 0; + + pnr = parse_seabear_header(filename, params, pnr); + + if (parse_seabear_csv_file(filename, params, pnr, "csv") < 0) { + return -1; + } + + return 0; +} + int parse_seabear_csv_file(const char *filename, char **params, int pnr, const char *csvtemplate) { int ret, i; diff --git a/core/qthelper.cpp b/core/qthelper.cpp index 2ba358fc0..45e402fc7 100644 --- a/core/qthelper.cpp +++ b/core/qthelper.cpp @@ -1519,3 +1519,136 @@ QString getUUID() uuidString.replace("{", "").replace("}", ""); return uuidString; } + +int parse_seabear_header(const char *filename, char **params, int pnr) +{ + QFile f(filename); + + f.open(QFile::ReadOnly); + QString parseLine = f.readLine(); + + /* + * Parse dive number from Seabear CSV header + */ + + while ((parseLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) { + if (parseLine.contains("//DIVE NR: ")) { + params[pnr++] = strdup("diveNro"); + params[pnr++] = strdup(parseLine.replace(QString::fromLatin1("//DIVE NR: "), QString::fromLatin1("")).toUtf8().data()); + break; + } + } + f.seek(0); + + /* + * Parse header - currently only interested in sample + * interval and hardware version. If we have old format + * the interval value is missing from the header. + */ + + while ((parseLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) { + if (parseLine.contains("//Hardware Version: ")) { + params[pnr++] = strdup("hw"); + params[pnr++] = strdup(parseLine.replace(QString::fromLatin1("//Hardware Version: "), QString::fromLatin1("\"Seabear ")).trimmed().append("\"").toUtf8().data()); + break; + } + } + f.seek(0); + + /* + * Grab the sample interval + */ + + while ((parseLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) { + if (parseLine.contains("//Log interval: ")) { + params[pnr++] = strdup("delta"); + params[pnr++] = strdup(parseLine.remove(QString::fromLatin1("//Log interval: ")).trimmed().remove(QString::fromLatin1(" s")).toUtf8().data()); + break; + } + } + f.seek(0); + + /* + * Dive mode, can be: OC, APNEA, BOTTOM TIMER, CCR, CCR SENSORBOARD + * Note that we scan over the "Log interval" on purpose + */ + + while ((parseLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) { + QString needle = "//Mode: "; + if (parseLine.contains(needle)) { + params[pnr++] = strdup("diveMode"); + params[pnr++] = strdup(parseLine.replace(needle, QString::fromLatin1("")).prepend("\"").append("\"").toUtf8().data()); + } + } + f.seek(0); + + while ((parseLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) { + } + + /* + * Parse CSV fields + */ + + parseLine = f.readLine().trimmed(); + + QStringList currColumns = parseLine.split(';'); + unsigned short index = 0; + Q_FOREACH (QString columnText, currColumns) { + if (columnText == "Time") { + params[pnr++] = strdup("timeField"); + params[pnr++] = intdup(index++); + } else if (columnText == "Depth") { + params[pnr++] = strdup("depthField"); + params[pnr++] = intdup(index++); + } else if (columnText == "Temperature") { + params[pnr++] = strdup("tempField"); + params[pnr++] = intdup(index++); + } else if (columnText == "NDT") { + params[pnr++] = strdup("ndlField"); + params[pnr++] = intdup(index++); + } else if (columnText == "TTS") { + params[pnr++] = strdup("ttsField"); + params[pnr++] = intdup(index++); + } else if (columnText == "pO2_1") { + params[pnr++] = strdup("o2sensor1Field"); + params[pnr++] = intdup(index++); + } else if (columnText == "pO2_2") { + params[pnr++] = strdup("o2sensor2Field"); + params[pnr++] = intdup(index++); + } else if (columnText == "pO2_3") { + params[pnr++] = strdup("o2sensor3Field"); + params[pnr++] = intdup(index++); + } else if (columnText == "Ceiling") { + /* TODO: Add support for dive computer reported ceiling*/ + params[pnr++] = strdup("ceilingField"); + params[pnr++] = intdup(index++); + } else if (columnText == "Tank pressure") { + params[pnr++] = strdup("pressureField"); + params[pnr++] = intdup(index++); + } else { + // We do not know about this value + qDebug() << "Seabear import found an un-handled field: " << columnText; + } + } + + /* Separator is ';' and the index for that in DiveLogImportDialog constructor is 2 */ + params[pnr++] = strdup("separatorIndex"); + params[pnr++] = intdup(2); + + /* And metric units */ + params[pnr++] = strdup("units"); + params[pnr++] = intdup(0); + + params[pnr] = NULL; + f.close(); + return pnr; +} + +char *intdup(int index) +{ + char tmpbuf[21]; + + snprintf(tmpbuf, sizeof(tmpbuf) - 2, "%d", index); + tmpbuf[20] = 0; + return strdup(tmpbuf); +} diff --git a/core/qthelper.h b/core/qthelper.h index e0e4da0c5..ff91b771a 100644 --- a/core/qthelper.h +++ b/core/qthelper.h @@ -47,5 +47,7 @@ extern "C" void subsurface_mkdir(const char *dir); void init_proxy(); QString getUUID(); QStringList imageExtensionFilters(); +char *intdup(int index); +extern "C" int parse_seabear_header(const char *filename, char **params, int pnr); #endif // QTHELPER_H diff --git a/core/qthelperfromc.h b/core/qthelperfromc.h index 4b2ef3d53..91fbde415 100644 --- a/core/qthelperfromc.h +++ b/core/qthelperfromc.h @@ -20,5 +20,6 @@ char *hashfile_name_string(); char *picturedir_string(); const char *subsurface_user_agent(); enum deco_mode decoMode(); +int parse_seabear_header(const char *filename, char **params, int pnr); #endif // QTHELPERFROMC_H diff --git a/desktop-widgets/divelogimportdialog.cpp b/desktop-widgets/divelogimportdialog.cpp index 5e019958f..51046216f 100644 --- a/desktop-widgets/divelogimportdialog.cpp +++ b/desktop-widgets/divelogimportdialog.cpp @@ -7,6 +7,7 @@ #include <QDrag> #include <QMimeData> #include <QRegExp> +#include "core/qthelper.h" static QString subsurface_mimedata = "subsurface/csvcolumns"; static QString subsurface_index = "subsurface/csvindex"; @@ -742,15 +743,6 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy) resultModel->setData(resultModel->index(0, i),headers.at(i),Qt::EditRole); } -char *intdup(int index) -{ - char tmpbuf[21]; - - snprintf(tmpbuf, sizeof(tmpbuf) - 2, "%d", index); - tmpbuf[20] = 0; - return strdup(tmpbuf); -} - int DiveLogImportDialog::setup_csv_params(QStringList r, char **params, int pnr) { params[pnr++] = strdup("dateField"); @@ -854,58 +846,9 @@ void DiveLogImportDialog::on_buttonBox_accepted() if (ui->knownImports->currentText() != "Manual import") { for (int i = 0; i < fileNames.size(); ++i) { if (ui->knownImports->currentText() == "Seabear CSV") { - char *params[40]; - int pnr = 0; - params[pnr++] = strdup("timeField"); - params[pnr++] = intdup(r.indexOf(tr("Sample time"))); - params[pnr++] = strdup("depthField"); - params[pnr++] = intdup(r.indexOf(tr("Sample depth"))); - params[pnr++] = strdup("tempField"); - params[pnr++] = intdup(r.indexOf(tr("Sample temperature"))); - params[pnr++] = strdup("po2Field"); - params[pnr++] = intdup(r.indexOf(tr("Sample pO₂"))); - params[pnr++] = strdup("o2sensor1Field"); - params[pnr++] = intdup(r.indexOf(tr("Sample sensor1 pO₂"))); - params[pnr++] = strdup("o2sensor2Field"); - params[pnr++] = intdup(r.indexOf(tr("Sample sensor2 pO₂"))); - params[pnr++] = strdup("o2sensor3Field"); - params[pnr++] = intdup(r.indexOf(tr("Sample sensor3 pO₂"))); - params[pnr++] = strdup("cnsField"); - params[pnr++] = intdup(r.indexOf(tr("Sample CNS"))); - params[pnr++] = strdup("ndlField"); - params[pnr++] = intdup(r.indexOf(tr("Sample NDL"))); - params[pnr++] = strdup("ttsField"); - params[pnr++] = intdup(r.indexOf(tr("Sample TTS"))); - params[pnr++] = strdup("stopdepthField"); - params[pnr++] = intdup(r.indexOf(tr("Sample stopdepth"))); - params[pnr++] = strdup("pressureField"); - params[pnr++] = intdup(r.indexOf(tr("Sample pressure"))); - params[pnr++] = strdup("setpointFiend"); - params[pnr++] = intdup(-1); - params[pnr++] = strdup("separatorIndex"); - params[pnr++] = intdup(ui->CSVSeparator->currentIndex()); - params[pnr++] = strdup("units"); - params[pnr++] = intdup(ui->CSVUnits->currentIndex()); - params[pnr++] = strdup("delta"); - params[pnr++] = strdup(delta.toUtf8().data()); - if (hw.length()) { - params[pnr++] = strdup("hw"); - params[pnr++] = strdup(hw.toUtf8().data()); - } - params[pnr++] = NULL; + parse_seabear_log(fileNames[i].toUtf8().data()); - if (parse_seabear_csv_file(fileNames[i].toUtf8().data(), - params, pnr - 1, "csv") < 0) { - return; - } - // Seabear CSV stores NDL and TTS in Minutes, not seconds - struct dive *dive = dive_table.dives[dive_table.nr - 1]; - for(int s_nr = 0 ; s_nr < dive->dc.samples ; s_nr++) { - struct sample *sample = dive->dc.sample + s_nr; - sample->ndl.seconds *= 60; - sample->tts.seconds *= 60; - } } else { char *params[49]; int pnr = 0; diff --git a/dives/TestDiveSeabearNewFormat.xml b/dives/TestDiveSeabearNewFormat.xml index 357dafa7a..626f07ed6 100644 --- a/dives/TestDiveSeabearNewFormat.xml +++ b/dives/TestDiveSeabearNewFormat.xml @@ -5,8 +5,8 @@ <divesites> </divesites> <dives> -<dive date='2009-10-10' time='05:32:41' duration='16:25 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='2' date='2012-10-01' time='06:22:00' duration='16:25 min'> + <divecomputer model='Seabear H3' deviceid='ffffffff' dctype='CCR'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='29.0 C' /> @@ -209,8 +209,8 @@ <sample time='17:15 min' depth='0.0 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='07:32:41' duration='16:25 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='3' date='2012-10-01' time='06:49:00' duration='16:25 min'> + <divecomputer model='Seabear H3' deviceid='ffffffff'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='26.0 C' /> @@ -413,8 +413,8 @@ <sample time='17:15 min' depth='0.0 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='09:32:41' duration='16:17 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='4' date='2012-10-01' time='07:07:00' duration='16:17 min'> + <divecomputer model='Seabear H3' deviceid='ffffffff' dctype='Freedive'> <depth max='70.1 m' mean='33.197 m' /> <temperature water='25.0 C' /> <sample time='0:01 min' depth='1.2 m' temp='25.0 C' /> @@ -1344,8 +1344,8 @@ <sample time='16:24 min' depth='0.1 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='11:32:41' duration='16:25 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='5' date='2012-10-01' time='07:24:00' duration='16:25 min'> + <divecomputer model='Seabear H3' deviceid='ffffffff'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='25.0 C' /> @@ -1548,10 +1548,10 @@ <sample time='17:15 min' depth='0.0 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='13:32:41' duration='16:25 min'> +<dive number='1' date='2012-10-01' time='06:02:00' duration='16:25 min'> <cylinder description='oxygen' o2='100.0%' use='oxygen' /> <cylinder description='diluent' use='diluent' /> - <divecomputer model='Imported from CSV' deviceid='ffffffff' dctype='CCR' no_o2sensors='3'> + <divecomputer model='Seabear T1' deviceid='ffffffff' dctype='CCR' no_o2sensors='3'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='26.0 C' sensor1='0.96 bar' sensor2='0.99 bar' sensor3='0.96 bar' /> @@ -1754,8 +1754,8 @@ <sample time='17:15 min' depth='0.0 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='15:32:41' duration='16:25 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='2' date='2012-10-01' time='06:22:00' duration='16:25 min'> + <divecomputer model='Seabear T1' deviceid='ffffffff' dctype='CCR'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='29.0 C' /> @@ -1958,8 +1958,8 @@ <sample time='17:15 min' depth='0.0 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='17:32:41' duration='16:25 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='3' date='2012-10-01' time='06:49:00' duration='16:25 min'> + <divecomputer model='Seabear T1' deviceid='ffffffff'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='26.0 C' /> @@ -2162,8 +2162,8 @@ <sample time='17:15 min' depth='0.0 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='19:32:41' duration='16:17 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='4' date='2012-10-01' time='07:07:00' duration='16:17 min'> + <divecomputer model='Seabear T1' deviceid='ffffffff' dctype='Freedive'> <depth max='70.1 m' mean='33.197 m' /> <temperature water='24.0 C' /> <sample time='0:01 min' depth='1.2 m' temp='25.0 C' /> @@ -3093,8 +3093,8 @@ <sample time='16:24 min' depth='0.1 m' /> </divecomputer> </dive> -<dive date='2009-10-10' time='21:32:41' duration='16:25 min'> - <divecomputer model='Imported from CSV' deviceid='ffffffff'> +<dive number='5' date='2012-10-01' time='07:24:00' duration='16:25 min'> + <divecomputer model='Seabear T1' deviceid='ffffffff'> <depth max='69.9 m' mean='32.928 m' /> <temperature water='25.0 C' /> <sample time='0:05 min' depth='1.0 m' temp='25.0 C' /> diff --git a/tests/testparse.cpp b/tests/testparse.cpp index fea2f441e..9cea8c6c8 100644 --- a/tests/testparse.cpp +++ b/tests/testparse.cpp @@ -4,6 +4,7 @@ #include "core/file.h" #include "core/divelist.h" #include <QTextStream> +#include "core/qthelper.h" /* We have to use a macro since QCOMPARE * can only be called from a test method @@ -42,15 +43,6 @@ void TestParse::cleanup() sqlite3_close(_sqlite3_handle); } -char *intdup(int index) -{ - char tmpbuf[21]; - - snprintf(tmpbuf, sizeof(tmpbuf) - 2, "%d", index); - tmpbuf[20] = 0; - return strdup(tmpbuf); -} - int TestParse::parseCSV(int units, std::string file) { // some basic file parsing tests @@ -252,116 +244,10 @@ void TestParse::testParseNewFormat() */ for (int i = 0; i < files.size(); ++i) { - QString delta; - QStringList currColumns; - QStringList headers; - QString file = QString::fromLatin1(SUBSURFACE_TEST_DATA "/dives/").append(files.at(i)); - QFile f(file); - - /* - * Parse the sample interval if available from CSV - * header. - */ - - f.open(QFile::ReadOnly); - while ((firstLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) { - if (firstLine.contains("//Log interval: ")) - delta = firstLine.remove(QString::fromLatin1("//Log interval: ")).trimmed().remove(QString::fromLatin1(" s")); - } - firstLine = f.readLine().trimmed(); - - /* - * Parse the field configuration from the CSV header. - */ - - currColumns = firstLine.split(';'); - Q_FOREACH (QString columnText, currColumns) { - if (columnText == "Time") { - headers.append("Sample time"); - } else if (columnText == "Depth") { - headers.append("Sample depth"); - } else if (columnText == "Temperature") { - headers.append("Sample temperature"); - } else if (columnText == "NDT") { - headers.append("Sample NDL"); - } else if (columnText == "TTS") { - headers.append("Sample TTS"); - } else if (columnText == "pO2_1") { - headers.append("Sample sensor1 pO₂"); - } else if (columnText == "pO2_2") { - headers.append("Sample sensor2 pO₂"); - } else if (columnText == "pO2_3") { - headers.append("Sample sensor3 pO₂"); - } else if (columnText == "Ceiling") { - headers.append("Sample ceiling"); - } else if (columnText == "Tank pressure") { - headers.append("Sample pressure"); - } else { - // We do not know about this value - qDebug() << "Seabear import found an un-handled field: " << columnText; - headers.append(""); - } - f.close(); - } - - /* - * Validate the parsing routine returns success. - */ - - char *params[42]; - int pnr = 0; - - params[pnr++] = strdup("timeField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample time"))); - params[pnr++] = strdup("depthField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample depth"))); - params[pnr++] = strdup("tempField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample temperature"))); - params[pnr++] = strdup("po2Field"); - params[pnr++] = intdup(headers.indexOf(tr("Sample pO₂"))); - params[pnr++] = strdup("o2sensor1Field"); - params[pnr++] = intdup(headers.indexOf(tr("Sample sensor1 pO₂"))); - params[pnr++] = strdup("o2sensor2Field"); - params[pnr++] = intdup(headers.indexOf(tr("Sample sensor2 pO₂"))); - params[pnr++] = strdup("o2sensor3Field"); - params[pnr++] = intdup(headers.indexOf(tr("Sample sensor3 pO₂"))); - params[pnr++] = strdup("cnsField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample CNS"))); - params[pnr++] = strdup("ndlField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample NDL"))); - params[pnr++] = strdup("ttsField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample TTS"))); - params[pnr++] = strdup("stopdepthField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample stopdepth"))); - params[pnr++] = strdup("pressureField"); - params[pnr++] = intdup(headers.indexOf(tr("Sample pressure"))); - params[pnr++] = strdup("setpointField"); - params[pnr++] = intdup(-1); - params[pnr++] = strdup("numberField"); - params[pnr++] = intdup(-1); - params[pnr++] = strdup("separatorIndex"); - params[pnr++] = intdup(2); - params[pnr++] = strdup("units"); - params[pnr++] = intdup(0); - params[pnr++] = strdup("delta"); - params[pnr++] = strdup(delta.toUtf8().data()); - params[pnr++] = NULL; - - QCOMPARE(parse_seabear_csv_file(file.toUtf8().data(), - params, pnr - 1, "csv"), 0); + QCOMPARE(parse_seabear_log(QString::fromLatin1(SUBSURFACE_TEST_DATA + "/dives/").append(files.at(i)).toLatin1().data()), 0); QCOMPARE(dive_table.nr, i + 1); - - /* - * Set artificial but static dive times so the result - * can be compared to saved one. - */ - - if (dive_table.nr > 0) { - dive = dive_table.dives[dive_table.nr - 1]; - dive->when = 1255152761 + 7200 * i; - dive->dc.when = 1255152761 + 7200 * i; - } } fprintf(stderr, "number of dives %d \n", dive_table.nr); diff --git a/xslt/csv2xml.xslt b/xslt/csv2xml.xslt index 960f48395..efe7c37ef 100644 --- a/xslt/csv2xml.xslt +++ b/xslt/csv2xml.xslt @@ -26,6 +26,8 @@ <xsl:param name="separatorIndex" select="separatorIndex"/> <xsl:param name="delta" select="delta"/> <xsl:param name="hw" select="hw"/> + <xsl:param name="diveNro" select="diveNro"/> + <xsl:param name="diveMode" select="diveMode"/> <xsl:output method="xml" indent="yes"/> <xsl:variable name="lf"><xsl:text> @@ -111,6 +113,12 @@ </xsl:attribute> </xsl:if> + <xsl:if test="string-length($diveNro) > 0"> + <xsl:attribute name="number"> + <xsl:value-of select="$diveNro"/> + </xsl:attribute> + </xsl:if> + <!-- If the dive is CCR, create oxygen and diluent cylinders --> <xsl:if test="$po2Field >= 0 or $setpointField >= 0 or $o2sensor1Field >= 0 or $o2sensor2Field >= 0 or $o2sensor3Field >= 0"> @@ -137,6 +145,23 @@ <xsl:copy-of select="number($o2sensor1Field >= 0) + number($o2sensor2Field >= 0) + number($o2sensor3Field >= 0)" /> </xsl:attribute> </xsl:if> + + <!-- Seabear specific dive modes --> + <xsl:if test="string-length($diveMode) > 0"> + <xsl:if test="$diveMode = 'OC' or $diveMode = 'APNEA' or $diveMode = 'CCR' or $diveMode = 'CCR SENSORBOARD'"> + <xsl:attribute name="dctype"> + <xsl:choose> + <xsl:when test="$diveMode = 'APNEA'"> + <xsl:value-of select="'Freedive'"/> + </xsl:when> + <xsl:when test="$diveMode = 'CCR' or $diveMode = 'CCR SENSORBOARD' "> + <xsl:value-of select="'CCR'"/> + </xsl:when> + </xsl:choose> + </xsl:attribute> + </xsl:if> + </xsl:if> + <xsl:call-template name="printLine"> <xsl:with-param name="line" select="substring-before(//csv, $lf)"/> <xsl:with-param name="lineno" select="'1'"/> |