Skip to content

Export data

Exporting is importing run backwards. Where an import reads the outside world and translates it into your internal vocabulary, an export reads a fully-identified internal time series and translates it back out — renaming through the same ID map, converting units, and writing the result to a file, database, or service. This is hop ⑤, the reverse of the import boundary: internal names and units go in, the outside world’s names and units come out. This guide covers the config file that drives it: timeSeriesExportRun.

The skeleton mirrors the import file element for element. A general block says where the data goes and how to write it, followed by one or more timeSeriesSet blocks that say which internal series to read out.

timeSeriesExportRun
└─ export
├─ general ← the destination + the writer + the mappings
│ ├─ exportType / exportTypeStandard (which writer/serializer)
│ ├─ folder + exportFileName (where the file goes)
│ │ …or serverUrl (a service instead of a file)
│ ├─ idMapId (internal → external names)
│ ├─ unitConversionsId / flagConversionsId (optional)
│ └─ exportTimeZone (how to write timestamps)
└─ timeSeriesSet(s) ← the INTERNAL series to READ (uses internal ids)
moduleInstanceId · parameterId · locationId/locationSetId
· timeSeriesType · timeStep

The same mental split as import, pointed the other way: timeSeriesSet speaks your language; general produces the outside world’s. The idMap is again the bridge — only now it runs internal → external. Compare this tree with the import anatomy; the shape is identical, import/general/timeSeriesSet becoming export/general/timeSeriesSet.

Where import picks a reader, export picks a writer (also called a serializer). The general block starts with three mutually exclusive ways to choose one — pick exactly one:

ElementUse whenExample value
exportTypeStandardThe destination is one of FEWS’s built-in serializers.pi, csv, netcdf
exportTypeYou’re using a general/named serializer that isn’t in the standard enum (the general tabular/CSV writer lives here).generalCsv
serializerClassName (+ binDir)You have a custom Java serializer.com.example.MyWriter

We’ll write out the hourly discharge we imported in the import walkthrough — the same RiverGauge_01 / Q.obs series, now leaving FEWS. Every step is the mirror of an import step.

  1. Point at the destination and pick the writer

    Section titled “Point at the destination and pick the writer”
    <general>
    <exportType>generalCsv</exportType>
    <folder>$EXPORT_FOLDER$/discharge</folder>
    <exportFileName>
    <name>discharge.csv</name>
    </exportFileName>

    Where import had folder + fileNamePatternFilter (which files to read), export has folder + exportFileName (what file to write). $EXPORT_FOLDER$ is a global property (in global.properties) so the path isn’t hard-coded per machine. Instead of a plain name you can build the filename from a prefix/suffix, or set useExternalLocationIdAsName to write one file per location.

  2. <exportTimeZone>
    <timeZoneName>GMT</timeZoneName>
    </exportTimeZone>

    The mirror of importTimeZone. Internally every value carries an explicit time, but the file needs a zone to render into — declare the zone the receiver expects with <timeZoneName> (e.g. GMT) or a <timeZoneOffset> like +01:00. Get it wrong and every timestamp in the output is shifted.

  3. <idMapId>IdExportObservations</idMapId>
    <!-- optional: <unitConversionsId>ExportUnits</unitConversionsId> -->
    <!-- optional: <flagConversionsId>ExportFlags</flagConversionsId> -->
    </general>

    idMapId names the ID map — but here it runs the other direction, turning RiverGauge_01 / Q.obs back into whatever the receiver calls them (say GAUGE-A / discharge). Add unitConversionsId to convert from your stored unit to the receiver’s on the way out, and flagConversionsId to translate FEWS quality flags into the receiver’s scheme.

  4. <timeSeriesSet>
    <moduleInstanceId>ImportObservations</moduleInstanceId>
    <valueType>scalar</valueType>
    <parameterId>Q.obs</parameterId>
    <locationId>RiverGauge_01</locationId>
    <timeSeriesType>external historical</timeSeriesType>
    <timeStep unit="hour" multiplier="1"/>
    <readWriteMode>read only</readWriteMode>
    </timeSeriesSet>

    Identical in form to the import’s timeSeriesSet, and that’s the point: it must reconstruct the same header the producer wrote, or it reads nothing. moduleInstanceId here is ImportObservations — the module that created the series — not the export’s own instance. This is the read side of the header-matching rule the import guide warns about.

Put together, the complete file:

Config/ModuleConfigFiles/ExportDischarge 1.00 default.xml
<?xml version="1.0" encoding="UTF-8"?>
<timeSeriesExportRun xmlns="http://www.wldelft.nl/fews">
<export>
<general>
<exportType>generalCsv</exportType>
<folder>$EXPORT_FOLDER$/discharge</folder>
<exportFileName>
<name>discharge.csv</name>
</exportFileName>
<idMapId>IdExportObservations</idMapId>
<exportTimeZone>
<timeZoneName>GMT</timeZoneName>
</exportTimeZone>
</general>
<timeSeriesSet>
<moduleInstanceId>ImportObservations</moduleInstanceId>
<valueType>scalar</valueType>
<parameterId>Q.obs</parameterId>
<locationId>RiverGauge_01</locationId>
<timeSeriesType>external historical</timeSeriesType>
<timeStep unit="hour" multiplier="1"/>
<readWriteMode>read only</readWriteMode>
</timeSeriesSet>
</export>
</timeSeriesExportRun>

As with import, you rarely write one timeSeriesSet per gauge. Swap locationId for a locationSetId and a single set exports the whole group, each member renamed through the same ID map:

<timeSeriesSet>
<moduleInstanceId>ImportObservations</moduleInstanceId>
<valueType>scalar</valueType>
<parameterId>Q.obs</parameterId>
<locationSetId>AllDischargeGauges</locationSetId>
<timeSeriesType>external historical</timeSeriesType>
<timeStep unit="hour" multiplier="1"/>
<readWriteMode>read only</readWriteMode>
</timeSeriesSet>

Combined with <exportFileName><useExternalLocationIdAsName>true</useExternalLocationIdAsName></exportFileName>, that writes one file per location in the set.

  • Export to a service instead of a file. Replace the folder + exportFileName pair with a serverUrl (with optional backupServerUrl and connectionTimeOutMillis, plus user / password for protected servers). The chosen serializer talks to that endpoint rather than writing to disk.
  • Different units for the receiver. Add unitConversionsId; FEWS converts from your stored unit to the receiver’s on the way out — the exact mirror of a unit conversion on import.
  • Exporting forecasts. Set timeSeriesType to external forecasting (or read a simulated series), and use forecastSelectionPeriod to pick which forecasts to write. Everything else is the same pipeline — see the lifecycle.
  • Marking missing values. By default gaps export as NaN; set exportMissingValue (numeric) or exportMissingValueString (text) to match what the receiver expects, or omitMissingValues to leave gaps out entirely.
  • Controlling precision and separators. precision fixes the number of fraction digits; columnSeparator / decimalSeparator tune tabular formats like generalCsv (e.g. ; and , for European CSVs).

The most-used fields; the full element list lives in timeSeriesExportRun.xsd.

general

FieldMeaning
exportType / exportTypeStandard / serializerClassNameWhich writer (pick one).
folder + exportFileNameWhere the file goes and what it’s called.
serverUrlA service destination instead of folder/file.
idMapIdThe internal→external ID map.
unitConversionsId, flagConversionsIdOptional unit / flag conversion, outward.
exportTimeZoneThe zone to render timestamps into.
exportMissingValue, omitMissingValuesHow to represent gaps.
precision, columnSeparator, decimalSeparatorNumeric and tabular formatting.

timeSeriesSet (the internal series to read)

FieldMeaning
moduleInstanceIdThe module that produced the series; must match its stored header.
valueTypescalar, grid, … (usually scalar).
parameterIdInternal parameter id (pre-mapping).
locationId / locationSetIdInternal location, or a whole set.
timeSeriesTypeexternal historical, external forecasting, or a simulated type.
timeStepe.g. unit="hour" multiplier="1", or unit="nonequidistant".
  • Nothing exports → the timeSeriesSet didn’t match a stored series. The read side must reconstruct the exact header the producer wrote — same moduleInstanceId, parameterId, locationId, timeSeriesType, and timeStep. A single mismatched field reads an empty series and writes an empty (or missing) file. This is the mirror of the import’s “imports but doesn’t display” trap.
  • External names look wrong → the ID map, read backwards. The same map that renamed data on import now renames it on export, internal → external. A map built only with import in mind can produce surprising output names — see the bidirectional note on ID mapping. Once any location is mapped, the map also filters: unmapped series are silently dropped from the export too.
  • Values off by a constant factor → missing unitConversionsId. Without an outward unit conversion, values are written in their stored unit, which may not be what the receiver expects.
  • readWriteMode is required, but inert here. The schema requires it on every timeSeriesSet, so include it (read only is sensible for an export, which only reads). Its semantics are honoured only by the Time Series Display; it does not make the export module behave differently, so don’t rely on it to.
  • A change has no effect → a higher-versioned file wins. Check for a sibling like ExportDischarge 1.01 default.xml. See how FEWS finds a file.
  1. Run the export (via a workflow, the same way you run an import) and read the log. An empty read — no series matched the timeSeriesSet — shows up here.
  2. Open the output. Look in $EXPORT_FOLDER$/discharge/ for discharge.csv (or the file the serializer produced) and confirm it exists and has rows.
  3. Confirm the external names and units. The location and parameter columns should show the receiver’s names (e.g. GAUGE-A / discharge), not your internal RiverGauge_01 / Q.obs — that proves the ID map ran outward. Check the magnitudes match the expected unit, and the timestamps the expected exportTimeZone.