Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileVEC.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileVEC.java	(revision 33661)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileVEC.java	(revision 33662)
@@ -5,4 +5,5 @@
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -10,4 +11,5 @@
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.BiConsumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -20,5 +22,4 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -36,4 +37,5 @@
 import org.openstreetmap.josm.plugins.fr.cadastre.edigeo.EdigeoRecord.Nature;
 import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
@@ -145,4 +147,8 @@
             return attributeValues.get(i);
         }
+
+        public boolean hasScdIdentifier(String id) {
+            return scdRef.identifier.equals(id);
+        }
     }
 
@@ -422,12 +428,12 @@
 
     private static final List<Predicate<ObjectBlock>> ignoredObjects = new ArrayList<>();
+    private static final List<Pair<Predicate<ObjectBlock>, BiConsumer<ObjectBlock, OsmPrimitive>>> postProcessors = new ArrayList<>();
 
     /**
      * Adds a predicate to ignore a special type of object.
      * @param predicate defines how to identify the object to ignore
-     * @return {@code true}
-     */
-    public static boolean addIgnoredObject(Predicate<ObjectBlock> predicate) {
-        return ignoredObjects.add(Objects.requireNonNull(predicate, "predicate"));
+     */
+    public static void addIgnoredObject(Predicate<ObjectBlock> predicate) {
+        ignoredObjects.add(Objects.requireNonNull(predicate, "predicate"));
     }
 
@@ -435,17 +441,56 @@
      * Adds a predicate to ignore a special type of object based on a key/value attribute.
      * @param key attribute key
-     * @param value attribute value
-     * @return {@code true}
-     */
-    public static boolean addIgnoredObject(String key, String value) {
-        return addIgnoredObject(o -> {
+     * @param values attribute values
+     */
+    public static void addIgnoredObject(String key, String... values) {
+        addIgnoredObject(predicate(key, values));
+    }
+
+    private static Predicate<ObjectBlock> predicate(String key, String... values) {
+        return o -> {
+            List<String> vals = Arrays.asList(values);
             for (int i = 0; i < o.nAttributes; i++) {
                 if (key.equals(o.attributeDefs.get(i).identifier)
-                        && value.equals(o.attributeValues.get(i))) {
+                        && (vals.isEmpty() || vals.contains(o.attributeValues.get(i)))) {
                     return true;
                 }
             }
             return false;
-        });
+        };
+    }
+
+    /**
+     * Adds a data postprocessor.
+     * @param consumer consumer that will update OSM primitive accordingly
+     * @param predicate predicate to match
+     */
+    public static void addObjectPostProcessor(BiConsumer<ObjectBlock, OsmPrimitive> consumer, Predicate<ObjectBlock> predicate) {
+        postProcessors.add(new Pair<>(Objects.requireNonNull(predicate, "predicate"), Objects.requireNonNull(consumer, "consumer")));
+    }
+
+    /**
+     * Adds a data postprocessor based on a key/value attribute.
+     * @param consumer consumer that will update OSM primitive accordingly
+     * @param key attribute key
+     * @param values attribute values
+     */
+    public static void addObjectPostProcessor(BiConsumer<ObjectBlock, OsmPrimitive> consumer, String key, String... values) {
+        postProcessors.add(new Pair<>(predicate(key, values), Objects.requireNonNull(consumer, "consumer")));
+    }
+
+    /**
+     * Adds a data postprocessor based on a SYM_id specific value.
+     * @param consumer consumer that will update OSM primitive accordingly
+     * @param symId value for "SYM_id" attribute.
+     * @param keyValues OSM attribute key/values (int the form {@code foo=bar;bar=baz})
+     */
+    public static void addObjectPostProcessor(String symId, String keyValues) {
+        postProcessors.add(new Pair<>(predicate("SYM_id", symId), (o, p) -> {
+            p.remove("SYM_id");
+            for (String tag : keyValues.split(";")) {
+                String[] kv = tag.split("=");
+                p.put(kv[0], kv[1]);
+            }
+        }));
     }
 
@@ -468,5 +513,5 @@
 
     private static BBox around(LatLon ll) {
-        final double r = 1e-7;
+        final double r = 1e-6;
         return new BBox(ll.getX() - r, ll.getY() - r, ll.getX() + r, ll.getY() + r);
     }
@@ -489,11 +534,19 @@
         for (ObjectBlock obj : getObjects()) {
             if (!ignoredObjects.stream().anyMatch(p -> p.test(obj))) {
+                OsmPrimitive p;
                 switch (obj.scdRef.kind) {
-                    case POINT: fillPoint(ds, proj, obj, obj.getConstructionRelations(), obj.getSemanticRelations()); break;
-                    case LINE: fillLine(ds, proj, obj, obj.getConstructionRelations(), obj.getSemanticRelations()); break;
-                    case AREA: fillArea(ds, proj, obj, obj.getConstructionRelations(), obj.getSemanticRelations()); break;
-                    case COMPLEX: break; // TODO (not used in PCI)
+                    case POINT: p = fillPoint(ds, proj, obj, obj.getConstructionRelations(), obj.getSemanticRelations()); break;
+                    case LINE: p = fillLine(ds, proj, obj, obj.getConstructionRelations(), obj.getSemanticRelations()); break;
+                    case AREA: p = fillArea(ds, proj, obj, obj.getConstructionRelations(), obj.getSemanticRelations()); break;
+                    case COMPLEX: // TODO (not used in PCI)
                     default: throw new IllegalArgumentException(obj.toString());
                 }
+                if (p != null) {
+                    for (Pair<Predicate<ObjectBlock>, BiConsumer<ObjectBlock, OsmPrimitive>> e : postProcessors) {
+                        if (e.a.test(obj)) {
+                            e.b.accept(obj, p);
+                        }
+                    }
+                }
             }
         }
@@ -501,9 +554,12 @@
     }
 
-    private static void addPrimitiveAndTags(DataSet ds, ObjectBlock obj, OsmPrimitive osm) {
+    private static <T extends OsmPrimitive> T addPrimitiveAndTags(DataSet ds, ObjectBlock obj, T osm) {
         for (int i = 0; i < obj.nAttributes; i++) {
-            osm.put(new Tag(obj.attributeDefs.get(i).identifier, obj.attributeValues.get(i)));
-        }
-        ds.addPrimitive(osm);
+            osm.put(obj.attributeDefs.get(i).identifier, obj.attributeValues.get(i));
+        }
+        if (osm.getDataSet() == null) {
+            ds.addPrimitive(osm);
+        }
+        return osm;
     }
 
@@ -527,18 +583,19 @@
     }
 
-    private static void fillPoint(DataSet ds, Projection proj, ObjectBlock obj,
+    private static Node fillPoint(DataSet ds, Projection proj, ObjectBlock obj,
             List<RelationBlock> constructionRelations, List<RelationBlock> semanticRelations) {
         assert constructionRelations.size() == 1 : constructionRelations;
-        List<NodeBlock> nodes = extract(NodeBlock.class, constructionRelations, RelationKind.IS_MADE_OF);
-        assert nodes.size() == 1 : nodes;
-        NodeBlock nb = nodes.get(0);
+        List<NodeBlock> blocks = extract(NodeBlock.class, constructionRelations, RelationKind.IS_MADE_OF);
+        assert blocks.size() == 1 : blocks;
+        NodeBlock nb = blocks.get(0);
         assert nb.nAttributes == 0;
         LatLon ll = proj.eastNorth2latlon(nb.getCoordinate());
-        //if (ds.searchNodes(around(ll)).isEmpty()) {
-        addPrimitiveAndTags(ds, obj, new Node(ll));
-        //}
-    }
-
-    private static void fillLine(DataSet ds, Projection proj, ObjectBlock obj,
+        List<Node> nodes = ds.searchNodes(around(ll));
+        assert nodes.size() <= 1;
+        Node n = nodes.isEmpty() ? new Node(ll) : nodes.get(0);
+        return addPrimitiveAndTags(ds, obj, n);
+    }
+
+    private static Way fillLine(DataSet ds, Projection proj, ObjectBlock obj,
             List<RelationBlock> constructionRelations, List<RelationBlock> semanticRelations) {
         assert constructionRelations.size() >= 1 : constructionRelations;
@@ -554,5 +611,5 @@
             if (newArcs.size() != 1) {
                 Logging.warn("Unable to process geometry of: " + obj);
-                return;
+                return null;
             }
             while (newArcs.size() < arcs.size()) {
@@ -579,11 +636,12 @@
         }
         assert w.getNodesCount() >= 2;
-        addPrimitiveAndTags(ds, obj, w);
-    }
-
-    private static void fillArea(DataSet ds, Projection proj, ObjectBlock obj,
+        return addPrimitiveAndTags(ds, obj, w);
+    }
+
+    private static OsmPrimitive fillArea(DataSet ds, Projection proj, ObjectBlock obj,
             List<RelationBlock> constructionRelations, List<RelationBlock> semanticRelations) {
         assert constructionRelations.size() >= 1 : constructionRelations;
         // TODO
+        return null;
     }
 
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/pci/EdigeoPciReader.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/pci/EdigeoPciReader.java	(revision 33661)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/pci/EdigeoPciReader.java	(revision 33662)
@@ -6,7 +6,13 @@
 import java.io.InputStream;
 import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.DataSet.UploadPolicy;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.AbstractReader;
@@ -20,6 +26,65 @@
 public class EdigeoPciReader extends AbstractReader {
 
+    private static final Map<String, List<String>> highways = new HashMap<>();
     static {
-        EdigeoFileVEC.addIgnoredObject("SYM_id", "31");
+        highways.put("motorway", Arrays.asList("Autoroute"));
+        highways.put("trunk", Arrays.asList("Rocade"));
+        highways.put("secondary", Arrays.asList("Avenue", "Boulevard", "Allee", "Allée", "Allees", "Allées", "Pont", "Port", "Route"));
+        highways.put("residential", Arrays.asList("Chemin", "Impasse", "Place", "Rue", "Quai", "Voie", "Grand Rue"));
+
+        EdigeoFileVEC.addIgnoredObject("SYM_id",
+                "31", // Connecting arrows between parcelles and numbers
+                "62", // "Sports ground, small streams". What the fuck France?
+                "64"  // "parking, terrace, overhang". What the fuck France?
+        );
+
+        EdigeoFileVEC.addObjectPostProcessor("19", "boundary=administrative;admin_level=8"); // Municipality limit trigger
+        EdigeoFileVEC.addObjectPostProcessor("21", "highway=road"); // Path
+        EdigeoFileVEC.addObjectPostProcessor("39", "barrier=wall"); // Common wall
+        EdigeoFileVEC.addObjectPostProcessor("40", "barrier=wall"); // Non-adjacent wall
+        EdigeoFileVEC.addObjectPostProcessor("45", "barrier=hedge"); // Common hedge
+        EdigeoFileVEC.addObjectPostProcessor("46", "barrier=hedge"); // Non-adjacent hedge
+
+        EdigeoFileVEC.addObjectPostProcessor((o, p) -> {
+            StringBuffer sb = new StringBuffer(p.get("TEX_id").trim());
+            p.remove("TEX_id");
+            for (String t : Arrays.asList("TEX2_id", "TEX3_id", "TEX4_id", "TEX5_id", "TEX6_id", "TEX7_id", "TEX8_id", "TEX9_id")) {
+                String v = p.get(t);
+                if (v == null) {
+                    break;
+                }
+                sb.append(' ').append(v.trim());
+                p.remove(t);
+            }
+            p.put("name", sb.toString());
+        }, "TEX_id");
+
+        EdigeoFileVEC.addObjectPostProcessor((o, p) -> {
+            p.put("highway", "road");
+            String name = p.get("name");
+            if (name != null && name.contains(" ")) {
+                String[] words = name.split(" ");
+                if (!setCorrectHighway(p, words)) {
+                    if (highways.values().stream().anyMatch(l -> l.contains(words[words.length - 1]))) {
+                        String[] newWords = new String[words.length];
+                        newWords[0] = words[words.length - 1];
+                        System.arraycopy(words, 0, newWords, 1, words.length - 1);
+                        p.put("name", String.join(" ", newWords));
+                        setCorrectHighway(p, newWords);
+                    }
+                }
+            }
+        }, o -> o.hasScdIdentifier("ZONCOMMUNI_id"));
+    }
+
+    private static boolean setCorrectHighway(OsmPrimitive p, String[] words) {
+        String type = words[0];
+        for (Entry<String, List<String>> e : highways.entrySet()) {
+            if (e.getValue().contains(type)) {
+                p.put("highway", e.getKey());
+                return true;
+            }
+        }
+        return false;
     }
 
