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.
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 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.
/* 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:
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
- Preset namespace and root. The
<presets>element must declare thetagging-preset-1.0namespace 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. - 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. - 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. - Field widgets.
<text>,<combo>, and<check>map onto the widget types JOSM renders; eachkeyattribute is the OSM key the widget writes, and thetextattribute is only the human label, never the stored value. - 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. - The core selector.
*[amenity=fuel][!name]reads as: any primitive (*) that hasamenity=fueland does not have anamekey. The!prefix is presence-negation, distinct fromname="", which would test for an empty value. throwWarningvsthrowOther.throwWarningfiles the issue at warning severity, which blocks upload by default until acknowledged;throwOtheris informational and never blocks, which suits the softer “no fuel detail” nudge.- Self-testing assertions.
assertMatchandassertNoMatchare 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 theStation name,Sells diesel, andSelf servicefields. If the menu entry is missing, the XML failed to parse. - Warning fires. Create a node, tag it
amenity=fuelonly, and pressValidate. The results panel must showMissing name on fuel stationunder Warnings. - Warning clears. Add
name=Example Fueland re-validate; the warning must disappear, proving the[!name]negation is evaluated live. - Assertions pass. With the rule loaded, check
Preferences → Data Validatorfor a source-error badge; a clean load meansassertMatch/assertNoMatchboth held. - Upload gate. Attempt an upload with the unnamed fuel node still present; JOSM must interrupt with the unresolved warning, confirming
throwWarningseverity 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, orthrowOther, optionally withfixAdd,fixRemove, orfixChangeKeyauto-fixes andassertMatch/assertNoMatchself-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.
Related Jump to heading
- Authoring OSM Validation Rules — the section this preset-plus-rule pairing belongs to.
- Authoring Osmose Rule DSL Checks — the server-side analogue that surfaces the same class of issue on the QA map.
- Building Python-Based OSM Validation Rules — a pipeline framework for enforcing house rules outside the editor.
- Tag Taxonomy & Key-Value Standards — the vocabulary reference the preset fields should follow.
- Flagging Deprecated OSM Tags in a Pipeline — a batch check that mirrors editor-time rules for imports.
- OSM Data Quality & Validation — the wider quality-assurance section around this topic.
Up one level: Authoring OSM Validation Rules.