Index: trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 4011)
@@ -2,12 +2,23 @@
 package org.openstreetmap.josm.gui.mappaint;
 
+import java.util.Collection;
+import java.util.List;
+
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
 
 public class Environment {
-    
+
     public OsmPrimitive osm;
     public MultiCascade mc;
     public String layer;
     public StyleSource source;
+
+    /**
+     * <p>When matching a child selector, the matching referrers will be stored.
+     * They can be accessed in {@link Instruction#execute(Environment)} to access
+     * tags from parent objects.</p>
+     */
+    private List<OsmPrimitive> matchingReferrers = null;
 
     public Environment(OsmPrimitive osm, MultiCascade mc, String layer, StyleSource source) {
@@ -18,3 +29,14 @@
     }
 
+    public Collection<OsmPrimitive> getMatchingReferrers() {
+        return matchingReferrers;
+    }
+
+    public void setMatchingReferrers(List<OsmPrimitive> refs) {
+        matchingReferrers = refs;
+    }
+
+    public void clearMatchingReferrers() {
+        matchingReferrers = null;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java	(revision 4011)
@@ -17,5 +17,4 @@
 import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.gui.mappaint.Cascade;
 import org.openstreetmap.josm.gui.mappaint.Environment;
@@ -174,11 +173,19 @@
             }
 
-            // FIXME: respect parent selector chain
             public String parent_tag(String key) {
-                for (Relation parent: OsmPrimitive.getFilteredList(env.osm.getReferrers(), Relation.class)) {
-                    String value = parent.get(key);
-                    if (value != null) return value;
-                }
-                return null;
+                if (env.getMatchingReferrers() == null) {
+                    // we don't have a matched parent, so just search all referrers
+                    for (OsmPrimitive parent : env.osm.getReferrers()) {
+                        String value = parent.get(key);
+                        if (value != null)
+                            return value;
+                    }
+                    return null;
+                }
+                if (env.getMatchingReferrers().isEmpty())
+                    return null;
+                // use always the first matching referrer to have consistency
+                // in an expression and declaration block
+                return env.getMatchingReferrers().iterator().next().get(key);
             }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 4011)
@@ -140,5 +140,6 @@
         for (MapCSSRule r : rules) {
             for (Selector s : r.selectors) {
-                if (s.applies(env)) {
+                env.clearMatchingReferrers();
+                if (s.matches(env)) { // as side effect env.matchingReferrers will be set (if s is a child selector)
                     if (s.getRange().contains(scale)) {
                         mc.range = Range.cut(mc.range, s.getRange());
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 4011)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.mappaint.mapcss;
 
+import java.util.ArrayList;
 import java.util.List;
 
@@ -15,31 +16,68 @@
 
 public interface Selector {
-    
-    public boolean applies(Environment e);
+
+    /**
+     * Apply the selector to the primitive and check if it matches.
+     *
+     * @param env the Environment. env.mc and env.layer are read-only when matching a selector.
+     * env.source is not needed. This method will set the matchingReferrers field of env as
+     * a side effect! Make sure to clear it before invoking this method.
+     * @return true, if the selector applies
+     */
+    public boolean matches(Environment env);
 
     public String getSubpart();
+
     public Range getRange();
 
-    public static class DescendentSelector implements Selector {
+    /**
+     * <p>Represents a child selector or a parent selector.</p>
+     * 
+     * <p>In addition to the standard CSS notation for child selectors, JOSM also supports
+     * an "inverse" notation:</p>
+     * <pre>
+     *    selector_a > selector_b { ... }       // the standard notation (child selector)
+     *    relation[type=route] > way { ... }    // example (all ways of a route)
+     * 
+     *    selector_a < selector_b { ... }       // the inverse notation (parent selector)
+     *    node[traffic_calming] < way { ... }   // example (way that has a traffic calming node)
+     * </pre>
+     *
+     */
+    public static class ChildOrParentSelector implements Selector {
         Selector a, b;
-        boolean child;
+        /** true, if this represents a parent selector (otherwise it is a child selector)
+         */
+        private final boolean parentSelector;
 
-        public DescendentSelector(Selector a, Selector b, boolean child) {
+        /**
+         * 
+         * @param a the first selector
+         * @param b the second selector
+         * @param parentSelector if true, this is a parent selector; otherwise a child selector
+         */
+        public ChildOrParentSelector(Selector a, Selector b, boolean parentSelector) {
             this.a = a;
             this.b = b;
-            this.child = child;
+            this.parentSelector = parentSelector;
         }
 
         @Override
-        public boolean applies(Environment e) {
-            if (!b.applies(e))
+        public boolean matches(Environment e) {
+            if (!b.matches(e))
                 return false;
 
             Environment e2 = new Environment(null, e.mc, e.layer, e.source);
-            if (child) {
-                for (OsmPrimitive osm : e.osm.getReferrers()) {
-                    e2.osm = osm;
-                    if (a.applies(e2))
-                        return true;
+            List<OsmPrimitive> matchingRefs = new ArrayList<OsmPrimitive>();
+            if (!parentSelector) {
+                for (OsmPrimitive ref : e.osm.getReferrers()) {
+                    e2.osm = ref;
+                    if (a.matches(e2)) {
+                        matchingRefs.add(ref);
+                    }
+                }
+                if (!matchingRefs.isEmpty()) {
+                    e.setMatchingReferrers(matchingRefs);
+                    return true;
                 }
             } else {
@@ -47,5 +85,5 @@
                     for (OsmPrimitive chld : ((Relation) e.osm).getMemberPrimitives()) {
                         e2.osm = chld;
-                        if (a.applies(e2))
+                        if (a.matches(e2))
                             return true;
                     }
@@ -53,5 +91,5 @@
                     for (Node n : ((Way) e.osm).getNodes()) {
                         e2.osm = n;
-                        if (a.applies(e2))
+                        if (a.matches(e2))
                             return true;
                     }
@@ -104,5 +142,5 @@
 
         @Override
-        public boolean applies(Environment e) {
+        public boolean matches(Environment e) {
             if (!baseApplies(e.osm))
                 return false;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.java	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.java	(revision 4011)
@@ -15,5 +15,5 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.FunctionExpression;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.LiteralExpression;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.DescendentSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
 import org.openstreetmap.josm.tools.Pair;
@@ -275,5 +275,5 @@
 
   final public Selector child_selector() throws ParseException {
-    boolean child = false;
+    boolean parentSelector = false;
     Selector sel1, sel2 = null;
     sel1 = selector();
@@ -285,9 +285,9 @@
       case GREATER:
         jj_consume_token(GREATER);
-                      child = true;
+                      parentSelector = false;
         break;
       case LESS:
         jj_consume_token(LESS);
-                                                 child = false;
+                                                           parentSelector = true;
         break;
       default:
@@ -304,5 +304,5 @@
       ;
     }
-      {if (true) return sel2 != null ? new DescendentSelector(sel1, sel2, child) : sel1;}
+      {if (true) return sel2 != null ? new ChildOrParentSelector(sel1, sel2, parentSelector) : sel1;}
     throw new Error("Missing return statement in function");
   }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj	(revision 4011)
@@ -20,5 +20,5 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.FunctionExpression;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.LiteralExpression;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.DescendentSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
 import org.openstreetmap.josm.tools.Pair;
@@ -251,5 +251,5 @@
 Selector child_selector() :
 {
-    boolean child = false;
+    boolean parentSelector = false;
     Selector sel1, sel2 = null;
 }
@@ -257,8 +257,8 @@
     sel1=selector() w()
     (
-        ( <GREATER> { child = true; } | <LESS> { child = false; } ) w()
+        ( <GREATER> { parentSelector = false; } | <LESS> { parentSelector = true; } ) w()
         sel2=selector() w()
     )?
-    { return sel2 != null ? new DescendentSelector(sel1, sel2, child) : sel1; }
+    { return sel2 != null ? new ChildOrParentSelector(sel1, sel2, parentSelector) : sel1; }
 }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserTokenManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserTokenManager.java	(revision 4010)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParserTokenManager.java	(revision 4011)
@@ -13,5 +13,5 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.FunctionExpression;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.LiteralExpression;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.DescendentSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
 import org.openstreetmap.josm.tools.Pair;
