Writing Custom JOSM Validation Presets Jump to heading

Make the JOSM editor raise a warning the moment a mapper selects a fuel station tagged amenity=fuel but left name empty — by shipping a tagging preset that offers the field and a MapCSS validator rule that flags its absence, both loaded from local files.

Prerequisites Jump to heading

Work through each item before loading anything; a preset that silently fails to appear is almost always a schema or encoding slip in one of these.

Conceptual minimum Jump to heading

A JOSM tagging preset and a JOSM validator rule are two separate mechanisms that happen to cooperate. The preset is a form definition: an XML file that declares a dialog with fields, so that when a mapper opens the preset for a selected element, JOSM offers structured inputs — a text box for name, a combo for fuel:diesel, a checkbox for self_service. A preset never enforces anything; it only makes correct tagging easier to enter. Enforcement lives in the validator, which JOSM drives from MapCSS. A MapCSS validator rule is a selector plus an assertion: it matches primitives by tag and geometry, and when a matched primitive violates the condition encoded in the selector, JOSM emits a warning or error into the validation results panel. The two are complementary — the preset shapes input, the validator polices output — and a house rule usually wants both so that the field the preset offers is the field the validator insists on.

The selector syntax is the load-bearing part. MapCSS matches on attribute presence and value: *[amenity=fuel] matches any primitive carrying that exact tag, and chaining a second condition with [!name] narrows the match to those additionally missing a name key. When such a primitive is selected or the validator runs, the rule body fires throwWarning with a human-readable message, and optionally a fixAdd/fixRemove auto-fix suggestion. Because MapCSS evaluation is scoped to the current selection and dataset in memory, the check is immediate: there is no server round-trip and no upload required, which is what makes it a live editing guardrail rather than a post-hoc audit. The diagram below traces how a single selected element flows through both mechanisms.

Preset and MapCSS validator evaluating one selected element A selected amenity=fuel element with no name feeds a tagging preset form above and a MapCSS validator rule below; the selector amenity=fuel plus not-name matches, and throwWarning writes a warning into the validation results panel. selected element amenity=fuel name = (empty) opens form is tested by tagging preset (XML) text: name combo: fuel:diesel check: self_service shapes input MapCSS validator rule *[amenity=fuel][!name] throwWarning: ... polices output writes tags matches → warns validation results Warning: Missing name on fuel station

Runnable solution Jump to heading

Two files. The first is the tagging preset, saved as house-rules-preset.xml. It declares one preset that targets nodes and closed ways carrying amenity=fuel and offers the fields a fuel station should have.

xml
<?xml version="1.0" encoding="UTF-8"?>
<presets xmlns="http://josm.openstreetmap.de/tagging-preset-1.0"
         author="data-quality-team"
         version="1.0"
         shortdescription="House Rules"
         description="Local tagging presets that mirror our validator checks.">
  <group name="House Rules">
    <item name="Fuel Station" type="node,closedway" preset_name_label="true">
      <key key="amenity" value="fuel"/>
      <text key="name" text="Station name" />
      <combo key="fuel:diesel" values="yes,no" text="Sells diesel" />
      <combo key="fuel:octane_95" values="yes,no" text="Sells petrol (95)" />
      <check key="self_service" value_on="yes" value_off="no" text="Self service" />
      <text key="operator" text="Operator" />
    </item>
  </group>
</presets>

The second file is the MapCSS validator rule, saved as house-rules-validator.mapcss. It raises a warning on any fuel station missing a name, and offers a paste-in fix hint.

css
/* house-rules-validator.mapcss
   Flags fuel stations that carry amenity=fuel but no name key. */

meta {
    title: "House Rules validator";
    version: "1.0";
    description: "Local QA checks that mirror the House Rules tagging preset.";
}

*[amenity=fuel][!name] {
    throwWarning: tr("Missing name on fuel station");
    assertMatch: "node amenity=fuel";
    assertNoMatch: "node amenity=fuel name=Shell";
}

/* A second, related check: fuel station with no fuel:* detail tags. */
*[amenity=fuel][!/^fuel:/] {
    throwOther: tr("Fuel station has no fuel:* detail tags");
}

Load both from Preferences:

text
Preferences → Tagging Presets → "+" → add house-rules-preset.xml
Preferences → Data Validator → Tag checker rules → "+" → add house-rules-validator.mapcss

After adding each file, restart is not required; JOSM re-reads the sources on dialog OK. Select a fuel-station element and run Validation (the “Validate” button on the selection, or the toolbar action) to see the warning appear.

Step-by-step walkthrough Jump to heading

  1. Preset namespace and root. The <presets> element must declare the tagging-preset-1.0 namespace exactly as shown; a wrong or missing namespace makes JOSM ignore the file silently, which is the single most common reason a new preset never appears in the menu.
  2. Item targeting. type="node,closedway" restricts the preset to the geometries a fuel station can legitimately be — a point or an enclosed building outline — so it never offers itself on a bare linear way.
  3. The fixed key. <key key="amenity" value="fuel"/> stamps the defining tag when the preset is applied, so the preset both matches existing fuel stations and creates new ones consistently.
  4. Field widgets. <text>, <combo>, and <check> map onto the widget types JOSM renders; each key attribute is the OSM key the widget writes, and the text attribute is only the human label, never the stored value.
  5. MapCSS meta block. The meta { title: ... } block names the rule set in the validator preferences list; without a title the source shows as an anonymous entry that is hard to toggle.
  6. The core selector. *[amenity=fuel][!name] reads as: any primitive (*) that has amenity=fuel and does not have a name key. The ! prefix is presence-negation, distinct from name="", which would test for an empty value.
  7. throwWarning vs throwOther. throwWarning files the issue at warning severity, which blocks upload by default until acknowledged; throwOther is informational and never blocks, which suits the softer “no fuel detail” nudge.
  8. Self-testing assertions. assertMatch and assertNoMatch are unit tests baked into the rule — JOSM evaluates them when the rule loads and reports a source error if the selector does not behave as asserted, so a typo surfaces immediately instead of at editing time.

Verification Jump to heading

Confirm both halves work before relying on them:

  • Preset appears. Open Presets → House Rules → Fuel Station; the dialog must list the Station name, Sells diesel, and Self service fields. If the menu entry is missing, the XML failed to parse.
  • Warning fires. Create a node, tag it amenity=fuel only, and press Validate. The results panel must show Missing name on fuel station under Warnings.
  • Warning clears. Add name=Example Fuel and re-validate; the warning must disappear, proving the [!name] negation is evaluated live.
  • Assertions pass. With the rule loaded, check Preferences → Data Validator for a source-error badge; a clean load means assertMatch/assertNoMatch both held.
  • Upload gate. Attempt an upload with the unnamed fuel node still present; JOSM must interrupt with the unresolved warning, confirming throwWarning severity is in effect.

Common errors and fixes Jump to heading

Symptom Root cause One-line fix
Preset never appears in menu Wrong or missing XML namespace Use the exact tagging-preset-1.0 namespace on <presets>.
JOSM reports “invalid character” on load File saved with a UTF-8 BOM Re-save as UTF-8 without BOM.
Rule loads but never warns Value test used instead of presence test Use [!name] for absence, not [name=""].
Source error badge on the MapCSS file assertMatch/assertNoMatch contradicts the selector Correct the selector or the assertion so they agree.
Warning does not block upload Used throwOther instead of throwWarning Switch to throwWarning for upload-blocking severity.
Combo writes wrong value text attribute confused with value Put stored values in values=, labels in text=.
Rule matches ways it should not Selector used * without a geometry guard Prefix with node, way, or area to scope geometry.

For house rules that must run outside the editor as well, mirror the same conditions in a batch check such as Flagging Deprecated OSM Tags in a Pipeline so an unedited import cannot bypass the guardrail.

Specification reference Jump to heading

JOSM’s validator is driven by MapCSS: a tag-checker rule is a MapCSS selector whose declaration block calls throwError, throwWarning, or throwOther, optionally with fixAdd, fixRemove, or fixChangeKey auto-fixes and assertMatch/assertNoMatch self-tests. Presence and absence are tested with [key] and [!key]. See the official JOSM Validator help and the MapCSS implementation notes for the exact grammar and the list of supported directives.

Frequently Asked Questions Jump to heading

Does the preset enforce the validator rule on its own?

No. A tagging preset only renders a form and, at most, stamps fixed keys when applied — it has no power to reject or warn about anything. Enforcement is entirely the validator’s job, driven by the separate MapCSS rule. Ship both so the field the preset offers is the field the validator insists on, and neither leans on the other for correctness.

What is the difference between throwWarning and throwError?

Both file an issue into the validation results, but severity differs. throwWarning marks the issue as a warning, which JOSM will interrupt an upload to have you acknowledge or resolve. throwError is the strongest severity and is meant for definite data corruption. throwOther is informational and never blocks upload, which suits soft nudges you do not want to gate a save.

How do I test a selector without waiting to hit the case while mapping?

Embed assertMatch and assertNoMatch in the rule body. JOSM evaluates these when it loads the MapCSS source: assertMatch names a primitive the selector must match, assertNoMatch one it must not. A mismatch raises a source error in the validator preferences on load, so a broken selector surfaces at load time instead of silently doing nothing while you edit.

Can I attach an automatic fix to a validator warning?

Yes. Add a fixAdd, fixChangeKey, or fixRemove directive to the rule body. fixAdd: "key=value" offers a one-click correction in the results panel. Auto-fixes are best reserved for unambiguous cases; for a missing free-text name there is no value to add automatically, so that rule warns without an auto-fix and leaves the mapper to type the real name.

Up one level: Authoring OSM Validation Rules.