Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 8236)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 8237)
@@ -286,4 +286,8 @@
         public Collection<Long> getWayIds() {
             return wayIds;
+        }
+
+        public List<Node> getNodes() {
+            return nodes;
         }
 
@@ -355,7 +359,6 @@
     private final List<Way> innerWays = new ArrayList<>();
     private final List<Way> outerWays = new ArrayList<>();
-    private final List<PolyData> innerPolygons = new ArrayList<>();
-    private final List<PolyData> outerPolygons = new ArrayList<>();
     private final List<PolyData> combinedPolygons = new ArrayList<>();
+    private final List<Node> openEnds = new ArrayList<>();
 
     private boolean incomplete;
@@ -391,8 +394,10 @@
         }
 
+        final List<PolyData> innerPolygons = new ArrayList<>();
+        final List<PolyData> outerPolygons = new ArrayList<>();
         createPolygons(innerWays, innerPolygons);
         createPolygons(outerWays, outerPolygons);
         if (!outerPolygons.isEmpty()) {
-            addInnerToOuters();
+            addInnerToOuters(innerPolygons, outerPolygons);
         }
     }
@@ -414,4 +419,8 @@
         for (JoinedWay jw: joinWays(waysToJoin)) {
             result.add(new PolyData(jw));
+            if (!jw.isClosed()) {
+                openEnds.add(jw.getNodes().get(0));
+                openEnds.add(jw.getNodes().get(jw.getNodes().size() - 1));
+            }
         }
     }
@@ -545,5 +554,5 @@
     }
 
-    private final void addInnerToOuters()  {
+    private final void addInnerToOuters(List<PolyData> innerPolygons, List<PolyData> outerPolygons)  {
 
         if (innerPolygons.isEmpty()) {
@@ -568,8 +577,4 @@
             }
         }
-
-        // Clear inner and outer polygons to reduce memory footprint
-        innerPolygons.clear();
-        outerPolygons.clear();
     }
 
@@ -593,3 +598,23 @@
         return combinedPolygons;
     }
+
+    public List<PolyData> getInnerPolygons() {
+        final List<PolyData> innerPolygons = new ArrayList<>();
+        createPolygons(innerWays, innerPolygons);
+        return innerPolygons;
+    }
+
+    public List<PolyData> getOuterPolygons() {
+        final List<PolyData> outerPolygons = new ArrayList<>();
+        createPolygons(outerWays, outerPolygons);
+        return outerPolygons;
+    }
+
+    /**
+     * Returns the start and end node of non-closed rings.
+     * @return the start and end node of non-closed rings.
+     */
+    public List<Node> getOpenEnds() {
+        return openEnds;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java	(revision 8236)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java	(revision 8237)
@@ -24,5 +24,4 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
-import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
@@ -59,5 +58,4 @@
     private static volatile ElemStyles styles;
 
-    private final List<List<Node>> nonClosedWays = new ArrayList<>();
     private final Set<String> keysCheckedByAnotherTest = new HashSet<>();
 
@@ -93,25 +91,4 @@
     }
 
-    private List<List<Node>> joinWays(Collection<Way> ways) {
-        List<List<Node>> result = new ArrayList<>();
-        List<Way> waysToJoin = new ArrayList<>();
-        for (Way way : ways) {
-            if (way.isClosed()) {
-                result.add(way.getNodes());
-            } else {
-                waysToJoin.add(way);
-            }
-        }
-
-        for (JoinedWay jw : Multipolygon.joinWays(waysToJoin)) {
-            if (!jw.isClosed()) {
-                nonClosedWays.add(jw.getNodes());
-            } else {
-                result.add(jw.getNodes());
-            }
-        }
-        return result;
-    }
-
     private GeneralPath createPath(List<Node> nodes) {
         GeneralPath result = new GeneralPath();
@@ -124,8 +101,8 @@
     }
 
-    private List<GeneralPath> createPolygons(List<List<Node>> joinedWays) {
+    private List<GeneralPath> createPolygons(List<Multipolygon.PolyData> joinedWays) {
         List<GeneralPath> result = new ArrayList<>();
-        for (List<Node> way : joinedWays) {
-            result.add(createPath(way));
+        for (Multipolygon.PolyData way : joinedWays) {
+            result.add(createPath(way.getNodes()));
         }
         return result;
@@ -165,5 +142,4 @@
     @Override
     public void visit(Relation r) {
-        nonClosedWays.clear();
         if (r.isMultipolygon()) {
             checkMembersAndRoles(r);
@@ -205,6 +181,4 @@
             }
 
-            List<List<Node>> innerWays = joinWays(polygon.getInnerWays()); // Side effect - sets nonClosedWays
-            List<List<Node>> outerWays = joinWays(polygon.getOuterWays());
             if (styles != null && !"boundary".equals(r.get("type"))) {
                 AreaElemStyle area = ElemStyles.getAreaElemStyle(r, false);
@@ -260,10 +234,5 @@
             }
 
-            List<Node> openNodes = new LinkedList<>();
-            for (List<Node> w : nonClosedWays) {
-                if (w.size()<1) continue;
-                openNodes.add(w.get(0));
-                openNodes.add(w.get(w.size() - 1));
-            }
+            List<Node> openNodes = polygon.getOpenEnds();
             if (!openNodes.isEmpty()) {
                 List<OsmPrimitive> primitives = new LinkedList<>();
@@ -276,25 +245,25 @@
 
             // For painting is used Polygon class which works with ints only. For validation we need more precision
-            List<GeneralPath> outerPolygons = createPolygons(outerWays);
-            for (List<Node> pdInner : innerWays) {
+            List<GeneralPath> outerPolygons = createPolygons(polygon.getOuterPolygons());
+            for (Multipolygon.PolyData pdInner : polygon.getInnerPolygons()) {
                 boolean outside = true;
                 boolean crossing = false;
-                List<Node> outerWay = null;
-                for (int i=0; i<outerWays.size(); i++) {
+                Multipolygon.PolyData outerWay = null;
+                for (int i = 0; i < polygon.getOuterPolygons().size(); i++) {
                     GeneralPath outer = outerPolygons.get(i);
-                    Intersection intersection = getPolygonIntersection(outer, pdInner);
+                    Intersection intersection = getPolygonIntersection(outer, pdInner.getNodes());
                     outside = outside & intersection == Intersection.OUTSIDE;
                     if (intersection == Intersection.CROSSING) {
                         crossing = true;
-                        outerWay = outerWays.get(i);
+                        outerWay = polygon.getOuterPolygons().get(i);
                     }
                 }
                 if (outside || crossing) {
                     List<List<Node>> highlights = new ArrayList<>();
-                    highlights.add(pdInner);
+                    highlights.add(pdInner.getNodes());
                     if (outside) {
                         addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside"), INNER_WAY_OUTSIDE, Collections.singletonList(r), highlights));
-                    } else if (crossing) {
-                        highlights.add(outerWay);
+                    } else {
+                        highlights.add(outerWay.getNodes());
                         addError(r, new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), CROSSING_WAYS, Collections.singletonList(r), highlights));
                     }
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 8236)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 8237)
@@ -9,4 +9,5 @@
 import java.util.regex.Pattern;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -14,4 +15,5 @@
 import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.gui.mappaint.Cascade;
 import org.openstreetmap.josm.gui.mappaint.ElemStyles;
@@ -410,4 +412,10 @@
             case "righthandtraffic":
                 return ExpressionFactory.Functions.is_right_hand_traffic(e);
+            case "unclosed_multipolygon":
+                return e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon() &&
+                        !MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) e.osm).getOpenEnds().isEmpty();
+            case "open_end":
+                // handling at org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector.MultipolygonOpenEndFinder
+                return true;
             }
             return false;
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 8236)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 8237)
@@ -16,4 +16,5 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.gui.mappaint.Environment;
 import org.openstreetmap.josm.gui.mappaint.Range;
@@ -219,4 +220,32 @@
         }
 
+        private class MultipolygonOpenEndFinder extends AbstractFinder {
+
+            @Override
+            public void visit(Way w) {
+                w.visitReferrers(innerVisitor);
+            }
+
+            public MultipolygonOpenEndFinder(Environment e) {
+                super(e);
+            }
+
+            private final AbstractVisitor innerVisitor = new AbstractFinder(e) {
+                @Override
+                public void visit(Relation r) {
+                    if (left.matches(e.withPrimitive(r))) {
+                        final List<Node> openEnds = MultipolygonCache.getInstance().get(Main.map.mapView, r).getOpenEnds();
+                        final int openEndIndex = openEnds.indexOf((Node) e.osm);
+                        if (openEndIndex >= 0) {
+                            e.parent = r;
+                            e.index = openEndIndex;
+                            e.count = openEnds.size();
+                        }
+                    }
+                }
+            };
+
+        }
+
         private final class CrossingFinder extends AbstractFinder {
             private CrossingFinder(Environment e) {
@@ -337,4 +366,12 @@
                         }
                     }
+                }
+            } else if (ChildOrParentSelectorType.CHILD.equals(type)
+                    && link.conds != null && !link.conds.isEmpty()
+                    && link.conds.get(0) instanceof Condition.PseudoClassCondition
+                    && "open_end".equals(((Condition.PseudoClassCondition) link.conds.get(0)).id)) {
+                if (e.osm instanceof Node) {
+                    e.osm.visitReferrers(new MultipolygonOpenEndFinder(e));
+                    return e.parent != null;
                 }
             } else if (ChildOrParentSelectorType.CHILD.equals(type)) {
