Related pieces
- Import time series — where
idMapIdis set - Define locations and parameters — the internal ids you map to
- Concept: How data flows through FEWS (hop ②) and the glossary entry
- Schema:
idMap.xsd
An ID map is the translation table at the boundary of FEWS (hop
②). It answers one question in both directions: this
external name — what do we call it internally, and vice versa? Every
import and every export names an ID map, and the map
is what lets a gauge the source calls GAUGE-A live inside FEWS as
RiverGauge_01.
An ID map file is a list of correspondences between external ids (what the
outside world uses) and internal ids (your FEWS vocabulary). It lives in
Config/IdMapFiles/ and is referenced by base name from an import or export via
idMapId.
EXTERNAL (the file/service) INTERNAL (FEWS) ───────────────────────── ──────────────── location "GAUGE-A" ⇆ location "RiverGauge_01" parameter "discharge" ⇆ parameter "Q.obs" └──────── idMap ────────┘There are two styles, and choosing the right one saves a lot of repetition.
A <map> element binds location and parameter together in one line — all
four ids at once:
<?xml version="1.0" encoding="UTF-8"?><idMap xmlns="http://www.wldelft.nl/fews" version="1.1"> <map internalLocation="RiverGauge_01" internalParameter="Q.obs" externalLocation="GAUGE-A" externalParameter="discharge"/> <map internalLocation="RiverGauge_02" internalParameter="Q.obs" externalLocation="GAUGE-B" externalParameter="discharge"/></idMap>Use when an external name only makes sense as a location+parameter pair — for example when the same external parameter string means different things at different stations.
Map parameter names once and location names once; FEWS combines them (every mapped parameter applies at every mapped location):
<?xml version="1.0" encoding="UTF-8"?><idMap xmlns="http://www.wldelft.nl/fews" version="1.1"> <parameter internal="Q.obs" external="discharge"/> <location internal="RiverGauge_01" external="GAUGE-A"/> <location internal="RiverGauge_02" external="GAUGE-B"/></idMap>Use when the external naming is consistent across locations (the usual case).
Two locations sharing one parameter needs 3 lines here vs 2 <map> lines — but at
50 gauges it’s 51 lines vs 50, and adding a second parameter is one line, not
50.
This is the single most important thing to understand about ID maps, straight
from the schema’s own documentation of enableOneToOneMapping:
When one-to-one mapping is enabled, the internal ids are used as external ids when not mapped explicitly. When this option is not enabled, the id map also acts as a filter when at least one location is mapped explicitly — everything that is not mapped is not imported or exported.
In plain terms:
If you instead want everything to pass through, mapping only the exceptions, opt in explicitly:
<idMap xmlns="http://www.wldelft.nl/fews" version="1.1"> <enableOneToOneMapping/> <!-- unmapped ids pass through unchanged (internal id == external id); only the entries below are renamed --> <location internal="RiverGauge_01" external="GAUGE-A"/></idMap>Listing hundreds of gauges by hand is miserable and error-prone. When external
and internal ids follow a naming convention, map them with a pattern instead.
locationIdPattern maps every location in an internal location
set by transforming its id:
<locationIdPattern internalLocationSet="AllDischargeGauges" internalLocationPattern="RiverGauge_*" externalLocationPattern="GAUGE-*"/>Here * is the part that varies: internal RiverGauge_01 ⇆ external GAUGE-01,
and so on for every member of the set. There are parameterIdFunction,
locationIdFunction, and qualifierIdFunction variants for more elaborate
transformations — reach for these once explicit lists become unwieldy.
Three optional switches, placed at the top of the file, change how matching works overall:
| Flag (empty element) | Effect |
|---|---|
<enableOneToOneMapping/> | Unmapped ids pass through unchanged instead of being filtered out. Good practice to state explicitly even when it would be the default. |
<enableCaseInsensitivity/> | External→internal matching ignores case on import (so Discharge matches discharge). |
<ignoreExternalQualifiersWhenMappingToInternal/> | Ignore external qualifiers when resolving to internal ids. |
For series distinguished by more than location + parameter, both the compact and
full forms accept internalQualifier1…4 / externalQualifier1…4 (order is
insignificant) and ensemble attributes (internalEnsemble,
externalEnsembleMemberIndex, …). You won’t need these on day one; know they
exist for when a plain location+parameter pair isn’t unique enough.
The map from the getting-started tutorial and the
import guide, shown in context. The import’s
idMapId points at this file’s base name:
Write the map in Config/IdMapFiles/:
<?xml version="1.0" encoding="UTF-8"?><idMap xmlns="http://www.wldelft.nl/fews" version="1.1"> <parameter internal="Q.obs" external="discharge"/> <location internal="RiverGauge_01" external="GAUGE-A"/></idMap>Reference it from the import’s general block:
<idMapId>IdImportObservations</idMapId>Note the base name only — no version suffix, no .xml.
Result: when the import reads GAUGE-A / discharge from the file, it
stores it internally as RiverGauge_01 / Q.obs. Any other station in the
file is dropped (this map explicitly maps a location, so it filters).
failOnUnmappableTimeSeries on.GAUGE_A ≠ GAUGE-A, and Discharge ≠
discharge unless you add <enableCaseInsensitivity/>. Punctuation and case
are the usual culprits.<map> for the exact pairs when it matters.IdImportObservations 1.01 default.xml. See how FEWS finds a
file.failOnUnmappableTimeSeries
/ logWarningsForUnmappableTimeSeries) and read the log — unmapped external
ids are listed there.RiverGauge_01 / Q.obs). If it’s there, the map matched.Related pieces
idMapId is setidMap.xsd