Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 7436)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(working copy)
@@ -179,6 +179,7 @@
 |   < CARET: "^" >
 |   < FULLSTOP: "." >
 |   < ELEMENT_OF: "∈" >
+|   < NOT_ELEMENT_OF: "∉" >
 |   < CROSSING: "⧉" >
 |   < COMMENT_START: "/*" > : COMMENT
 |   < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from
@@ -534,6 +535,8 @@
             |
                 <ELEMENT_OF> { type = Selector.ChildOrParentSelectorType.ELEMENT_OF; }
             |
+                <NOT_ELEMENT_OF> { type = Selector.ChildOrParentSelectorType.NOT_ELEMENT_OF; }
+            |
                 <CROSSING> { type = Selector.ChildOrParentSelectorType.CROSSING; }
             )
             w()
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 7436)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(working copy)
@@ -25,16 +25,16 @@
 
 /**
  * MapCSS selector.
- * 
+ *
  * A rule has two parts, a selector and a declaration block
  * e.g.
  * <pre>
- * way[highway=residential]    
- * { width: 10; color: blue; } 
+ * way[highway=residential]
+ * { width: 10; color: blue; }
  * </pre>
- * 
+ *
  * The selector decides, if the declaration block gets applied or not.
- * 
+ *
  * All implementing classes of Selector are immutable.
  */
 public interface Selector {
@@ -48,27 +48,32 @@
      * @return true, if the selector applies
      */
     boolean matches(Environment env);
-    
+
     String getSubpart();
 
     Range getRange();
-    
+
     /**
      * Create an "optimized" copy of this selector that omits the base check.
-     * 
+     *
      * For the style source, the list of rules is preprocessed, such that
      * there is a separate list of rules for nodes, ways, ...
-     * 
+     *
      * This means that the base check does not have to be performed
      * for each rule, but only once for each primitive.
-     * 
+     *
      * @return a selector that is identical to this object, except the base of the
      * "rightmost" selector is not checked
      */
     Selector optimizedBaseCheck();
 
     public static enum ChildOrParentSelectorType {
-        CHILD, PARENT, ELEMENT_OF, CROSSING, SIBLING
+        CHILD,
+        PARENT,
+        ELEMENT_OF,
+        NOT_ELEMENT_OF,
+        CROSSING,
+        SIBLING
     }
 
     /**
@@ -265,8 +270,11 @@
             if (!right.matches(e))
                 return false;
 
-            if (ChildOrParentSelectorType.ELEMENT_OF.equals(type)) {
+            boolean elementOf = ChildOrParentSelectorType.ELEMENT_OF.equals(type);
+            boolean notElementOf = ChildOrParentSelectorType.NOT_ELEMENT_OF.equals(type);
 
+            if (elementOf || notElementOf) {
+
                 if (e.osm instanceof Node || e.osm.getDataSet() == null) {
                     // nodes cannot contain elements
                     return false;
@@ -308,7 +316,7 @@
                     containsFinder.visit(e.osm.getDataSet().allPrimitives());
                 }
 
-                return e.child != null;
+                return elementOf ? e.child != null : e.child == null;
 
             } else if (ChildOrParentSelectorType.CROSSING.equals(type) && e.osm instanceof Way) {
                 e.parent = e.osm;
@@ -379,7 +387,7 @@
         public Range getRange() {
             return right.getRange();
         }
-        
+
         @Override
         public Selector optimizedBaseCheck() {
             return new ChildOrParentSelector(left, link, right.optimizedBaseCheck(), type);
@@ -472,7 +480,7 @@
         public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
             super(base, zoom, conds, subpart);
         }
-        
+
         public boolean matchesConditions(Environment e) {
             return super.matches(e);
         }
@@ -487,7 +495,7 @@
             return matchesBase(e) && super.matches(e);
         }
     }
-    
+
     public static class OptimizedGeneralSelector extends AbstractSelector {
         public final String base;
         public final Range range;
@@ -509,14 +517,14 @@
             }
             this.subpart = subpart;
         }
-        
+
         public OptimizedGeneralSelector(String base, Range range, List<Condition> conds, String subpart) {
             super(conds);
             this.base = base;
             this.range = range;
             this.subpart = subpart;
         }
-        
+
         public OptimizedGeneralSelector(GeneralSelector s) {
             this(s.base, s.range, s.conds, s.subpart);
         }
@@ -571,7 +579,7 @@
         public Selector optimizedBaseCheck() {
             throw new UnsupportedOperationException();
         }
-        
+
         public static Range fromLevel(int a, int b) {
             if (a > b)
                 throw new AssertionError();
@@ -595,7 +603,7 @@
             // or similar level are displayed at the given scale
             return 2.0 * Math.PI * R / Math.pow(2.0, lvl) / 2.56;
         }
-        
+
         public static int scale2level(double scale) {
             if (scale < 0)
                 throw new IllegalArgumentException();
