Index: trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/command/ChangePropertyCommand.java	(revision 6538)
@@ -221,3 +221,7 @@
         return children;
     }
+
+    public Map<String, String> getTags() {
+        return Collections.unmodifiableMap(tags);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/command/Command.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/Command.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/command/Command.java	(revision 6538)
@@ -86,5 +86,5 @@
      */
     public Command() {
-        this.layer = Main.main.getEditLayer();
+        this.layer = Main.main == null ? null : Main.main.getEditLayer();
     }
 
Index: trunk/src/org/openstreetmap/josm/data/validation/TestError.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/TestError.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/data/validation/TestError.java	(revision 6538)
@@ -219,4 +219,8 @@
     }
 
+    public void setTester(Test tester) {
+        this.tester = tester;
+    }
+
     /**
      * Gets the code
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 6538)
@@ -14,4 +14,6 @@
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.openstreetmap.josm.command.ChangePropertyCommand;
@@ -29,4 +31,5 @@
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
@@ -173,11 +176,57 @@
          */
         boolean matchesPrimitive(OsmPrimitive primitive) {
+            return whichSelectorMatchesPrimitive(primitive) != null;
+        }
+
+        Selector whichSelectorMatchesPrimitive(OsmPrimitive primitive) {
             final Environment env = new Environment().withPrimitive(primitive);
             for (Selector i : selector) {
                 if (i.matches(env)) {
-                    return true;
-                }
-            }
-            return false;
+                    return i;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Determines the {@code index}-th key/value/tag (depending on {@code type}) of the {@link Selector.GeneralSelector}.
+         */
+        static String determineArgument(Selector.GeneralSelector matchingSelector, int index, String type) {
+            try {
+                final Condition c = matchingSelector.getConditions().get(index);
+                final Tag tag = c instanceof Condition.KeyCondition
+                        ? ((Condition.KeyCondition) c).asTag()
+                        : c instanceof Condition.KeyValueCondition
+                        ? ((Condition.KeyValueCondition) c).asTag()
+                        : null;
+                if (tag == null) {
+                    return null;
+                } else if ("key".equals(type)) {
+                    return tag.getKey();
+                } else if ("value".equals(type)) {
+                    return tag.getValue();
+                } else if ("tag".equals(type)) {
+                    return tag.toString();
+                }
+            } catch (IndexOutOfBoundsException ignore) {
+            }
+            return null;
+        }
+
+        /**
+         * Replaces occurrences of {@code {i.key}}, {@code {i.value}}, {@code {i.tag}} in {@code s} by the corresponding
+         * key/value/tag of the {@code index}-th {@link Condition} of {@code matchingSelector}.
+         */
+        static String insertArguments(Selector matchingSelector, String s) {
+            if (!(matchingSelector instanceof Selector.GeneralSelector) || s == null) {
+                return s;
+            }
+            final Matcher m = Pattern.compile("\\{(\\d+)\\.(key|value|tag)\\}").matcher(s);
+            final StringBuffer sb = new StringBuffer();
+            while (m.find()) {
+                m.appendReplacement(sb, determineArgument((Selector.GeneralSelector) matchingSelector, Integer.parseInt(m.group(1)), m.group(2)));
+            }
+            m.appendTail(sb);
+            return sb.toString();
         }
 
@@ -193,11 +242,16 @@
                 return null;
             }
+            final Selector matchingSelector = whichSelectorMatchesPrimitive(p);
             Collection<Command> cmds = new LinkedList<Command>();
             for (PrimitiveToTag toTag : change) {
                 final Tag tag = toTag.apply(p);
-                cmds.add(new ChangePropertyCommand(p, tag.getKey(), tag.getValue()));
+                final String key = insertArguments(matchingSelector, tag.getKey());
+                final String value = insertArguments(matchingSelector, tag.getValue());
+                cmds.add(new ChangePropertyCommand(p, key, value));
             }
             for (Map.Entry<String, String> i : keyChange.entrySet()) {
-                cmds.add(new ChangePropertyKeyCommand(p, i.getKey(), i.getValue()));
+                final String oldKey = insertArguments(matchingSelector, i.getKey());
+                final String newKey = insertArguments(matchingSelector, i.getValue());
+                cmds.add(new ChangePropertyKeyCommand(p, oldKey, newKey));
             }
             return new SequenceCommand(tr("Fix of {0}", getDescription()), cmds);
@@ -231,4 +285,24 @@
         }
 
+        /**
+         * Constructs a {@link TestError} for the given primitive, or returns null if the primitive does not give rise to an error.
+         *
+         * @param p the primitive to construct the error for
+         * @return an instance of {@link TestError}, or returns null if the primitive does not give rise to an error.
+         */
+        TestError getErrorForPrimitive(OsmPrimitive p) {
+            final Selector matchingSelector = whichSelectorMatchesPrimitive(p);
+            if (matchingSelector != null) {
+                final Command fix = fixPrimitive(p);
+                final String description = TagCheck.insertArguments(matchingSelector, getDescription());
+                if (fix != null) {
+                    return new FixableTestError(null, getSeverity(), description, 3000, p, fix);
+                } else {
+                    return new TestError(null, getSeverity(), description, 3000, p);
+                }
+            } else {
+                return null;
+            }
+        }
     }
 
@@ -240,11 +314,8 @@
     public void visit(OsmPrimitive p) {
         for (TagCheck check : checks) {
-            if (check.matchesPrimitive(p)) {
-                final Command fix = check.fixPrimitive(p);
-                if (fix != null) {
-                    errors.add(new FixableTestError(this, check.getSeverity(), check.getDescription(), 3000, p, fix));
-                } else {
-                    errors.add(new TestError(this, check.getSeverity(), check.getDescription(), 3000, p));
-                }
+            final TestError error = check.getErrorForPrimitive(p);
+            if (error != null) {
+                error.setTester(this);
+                errors.add(error);
             }
         }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 6538)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.mappaint.Cascade;
@@ -161,4 +162,8 @@
         public boolean applies(Environment env) {
             return op.eval(env.osm.get(k), v);
+        }
+
+        public Tag asTag() {
+            return new Tag(k, v);
         }
 
@@ -252,4 +257,8 @@
         }
 
+        public Tag asTag() {
+            return new Tag(label);
+        }
+
         @Override
         public String toString() {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java	(revision 6538)
@@ -431,13 +431,5 @@
             }
             Matcher m = Pattern.compile(pattern, f).matcher(target);
-            if (m.matches()) {
-                List<String> result = new ArrayList<String>(m.groupCount() + 1);
-                for (int i = 0; i <= m.groupCount(); i++) {
-                    result.add(m.group(i));
-                }
-                return result;
-            } else {
-                return null;
-            }
+            return Utils.getMatches(m);
         }
 
@@ -450,13 +442,5 @@
         public static List<String> regexp_match(String pattern, String target) {
             Matcher m = Pattern.compile(pattern).matcher(target);
-            if (m.matches()) {
-                List<String> result = new ArrayList<String>(m.groupCount() + 1);
-                for (int i = 0; i <= m.groupCount(); i++) {
-                    result.add(m.group(i));
-                }
-                return result;
-            } else {
-                return null;
-            }
+            return Utils.getMatches(m);
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 6538)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.mappaint.mapcss;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.regex.PatternSyntaxException;
@@ -231,4 +232,8 @@
             return true;
         }
+
+        public List<Condition> getConditions() {
+            return Collections.unmodifiableList(conds);
+        }
     }
 
@@ -310,6 +315,5 @@
         @Override
         public boolean matches(Environment e) {
-            if (!matchesBase(e)) return false;
-            return matchesConditions(e);
+            return matchesBase(e) && matchesConditions(e);
         }
 
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 6537)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 6538)
@@ -38,4 +38,5 @@
 import java.util.Iterator;
 import java.util.List;
+import java.util.regex.Matcher;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.ZipFile;
@@ -835,3 +836,22 @@
         return String.format("%d %s %d %s", days, trn("day", "days", days), elapsedTime/3600000, tr("h"));
     }
+
+    /**
+     * Returns a list of capture groups if {@link Matcher#matches()}, or {@code null}.
+     * The first element (index 0) is the complete match.
+     * Further elements correspond to the parts in parentheses of the regular expression.
+     * @param m the matcher
+     * @return a list of capture groups if {@link Matcher#matches()}, or {@code null}.
+     */
+    public static List<String> getMatches(final Matcher m) {
+        if (m.matches()) {
+            List<String> result = new ArrayList<String>(m.groupCount() + 1);
+            for (int i = 0; i <= m.groupCount(); i++) {
+                result.add(m.group(i));
+            }
+            return result;
+        } else {
+            return null;
+        }
+    }
 }
