diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DOValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DOValidator.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e61f5d7edf2360632fffaa3101993a0fa879192
--- /dev/null
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DOValidator.java
@@ -0,0 +1,145 @@
+/**
+ *  Copyright (c) 2019 CentraleSupélec & EDF.
+ *  All rights reserved. This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License v1.0
+ *  which accompanies this distribution, and is available at
+ *  http://www.eclipse.org/legal/epl-v10.html
+ * 
+ *  This file is part of the RiseClipse tool
+ *  
+ *  Contributors:
+ *      Computer Science Department, CentraleSupélec
+ *      EDF R&D
+ *  Contacts:
+ *      dominique.marcadet@centralesupelec.fr
+ *      aurelie.dehouck-neveu@edf.fr
+ *  Web site:
+ *      http://wdi.supelec.fr/software/RiseClipse/
+ */
+package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataAttribute;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
+import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
+
+public class DOValidator {
+
+    private String cdc;
+    private HashMap< String, DataAttribute > daMap;
+
+    public DOValidator( CDC cdc ) {
+        this.cdc = cdc.getName();
+        this.daMap = new HashMap<>(); // link between DAI (name) and its respective DataAttribute
+        
+        for( DataAttribute da : cdc.getDataAttribute() ) {
+            this.daMap.put( da.getName(), da );
+        }
+    }
+
+    public boolean validateDO( DO do_, DiagnosticChain diagnostics ) {
+        AbstractRiseClipseConsole.getConsole().verbose( "validateDO( " + do_.getName() + " )" );
+        boolean res = true;
+        HashSet< String > checkedDA = new HashSet<>();
+
+        if( do_.getRefersToDOType() == null ) {
+            AbstractRiseClipseConsole.getConsole().warning( "validateDO: DO " + do_.getName() + " has no RefersToDOType" );
+        }
+        else {
+            for( DA da : do_.getRefersToDOType().getDA() ) {
+                AbstractRiseClipseConsole.getConsole().verbose( "validateDO on DA " + da.getName() + " (line" + da.getLineNumber() + ")" );
+    
+                // Test if DA is a possible DA in this DO
+                if( ! daMap.containsKey( da.getName() ) ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.ERROR,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "DA " + da.getName() + " (line" + da.getLineNumber() + ") not found in CDC",
+                            new Object[] { do_, cdc } ));
+                    res = false;
+                    continue;
+                }
+    
+                // Control of DAI presence in DO
+                updateCompulsory( da, checkedDA, diagnostics );
+            }
+        }
+
+        // Verify all necessary DA were present
+        if( ! daMap.values().stream()
+                .map( x -> checkCompulsory( do_, x, checkedDA, diagnostics ) )
+                .reduce( ( a, b ) -> a && b ).get() ) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "DO (line " + do_.getLineNumber() + ") does not contain all mandatory DA from CDC ",
+                    new Object[] { do_, cdc } ));
+            res = false;
+        }
+        return res;
+    }
+
+    public boolean checkCompulsory( DO do_, DataAttribute da, HashSet< String > checked, DiagnosticChain diagnostics ) {
+        switch( da.getPresCond() ) {
+        case "M":
+            if( ! checked.contains( da.getName() )) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "DA " + da.getName() + " not found in DO (line " + do_.getLineNumber() + ")",
+                        new Object[] { da } ));
+                return false;
+            }
+            break;
+        default:
+            AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: DOValidator.checkCompulsory( " + da.getPresCond() + " )" );
+            break;
+        }
+        return true;
+    }
+
+    public boolean updateCompulsory( DA da, HashSet< String > checked, DiagnosticChain diagnostics ) {
+        switch( daMap.get( da.getName() ).getPresCond() ) {
+        case "M":
+        case "O":
+            if( checked.contains( da.getName() ) ) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "DA " + da.getName() + " (line " + da.getLineNumber() + ") cannot appear more than once",
+                        new Object[] { da } ));
+                return false;
+            }
+            else {
+                checked.add( da.getName() );
+                break;
+            }
+        case "F":
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "DA " + da.getName() + " (line " + da.getLineNumber() + ") is forbidden",
+                    new Object[] { da } ));
+            return false;
+        default:
+            AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: DOIValidator.updateCompulsory( " + daMap.get( da.getName() ).getPresCond() + " )" );
+            break;
+        }
+        return true;
+    }
+
+}
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java
new file mode 100644
index 0000000000000000000000000000000000000000..b288c585b55777dbde4b8090f86cc5d65eacf049
--- /dev/null
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java
@@ -0,0 +1,173 @@
+/**
+ *  Copyright (c) 2019 CentraleSupélec & EDF.
+ *  All rights reserved. This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License v1.0
+ *  which accompanies this distribution, and is available at
+ *  http://www.eclipse.org/legal/epl-v10.html
+ * 
+ *  This file is part of the RiseClipse tool
+ *  
+ *  Contributors:
+ *      Computer Science Department, CentraleSupélec
+ *      EDF R&D
+ *  Contacts:
+ *      dominique.marcadet@centralesupelec.fr
+ *      aurelie.dehouck-neveu@edf.fr
+ *  Web site:
+ *      http://wdi.supelec.fr/software/RiseClipse/
+ */
+package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.AbstractLNClass;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataObject;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.LNClass;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.AnyLNClass;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
+import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
+
+public class LNodeTypeValidator {
+
+    private String lnClass;
+    private HashMap< String, DataObject > doMap;
+    private HashMap< String, DOValidator > cdcMap;
+
+    public LNodeTypeValidator( LNClass lnClass ) {
+        this.lnClass = lnClass.getName();
+        this.doMap = new HashMap<>(); // link between DOI (name) and its respective DataObject
+        this.cdcMap = new HashMap<>(); // link between CDC (name) and its respective DOIValidator
+        
+        generateValidators( doMap, cdcMap, lnClass );
+
+        // LNClass hierarchy taken into account
+        AbstractLNClass parent = lnClass.getRefersToAbstractLNClass();
+        while( parent != null ) {
+            generateValidators( doMap, cdcMap, parent );
+            parent = parent.getRefersToAbstractLNClass();
+        }
+
+    }
+
+    private void generateValidators( HashMap< String, DataObject > doMap, HashMap< String, DOValidator > cdcMap, AnyLNClass lnClass ) {
+        for( DataObject dObj : lnClass.getDataObject() ) {
+            doMap.put( dObj.getName(), dObj );
+            if( dObj.getRefersToCDC() != null ) {
+                if( ! cdcMap.containsKey( dObj.getRefersToCDC().getName() )) {
+                    cdcMap.put( dObj.getRefersToCDC().getName(), new DOValidator( dObj.getRefersToCDC() ));
+                }
+            }
+        }
+    }
+
+    public boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) {
+        boolean res = true;
+
+        HashSet< String > checkedDO = new HashSet<>();
+
+        for( DO do_ : lNodeType.getDO() ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "validateDOI( " + do_.getName() + " )" );
+
+            // Test if DOI is a possible DOI in this LN
+            if( ! doMap.containsKey( do_.getName() ) ) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "DO " + do_.getName() + " in LN at line " + lNodeType.getLineNumber() + " not found in LNClass " + lNodeType.getLnClass(),
+                        new Object[] { lNodeType } ));
+                continue;
+            }
+
+            // Control of DOI presence in LN  
+            updateCompulsory( do_, checkedDO, diagnostics );
+
+            // Validation of DOI content
+            if( ! validateDO( do_, diagnostics ) ) {
+                res = false;
+            }
+
+        }
+
+        // Verify all necessary DOI were present
+        if( ! doMap.values().stream()
+                .map( x -> checkCompulsory( lNodeType, x, checkedDO, diagnostics ))
+                .reduce( ( a, b ) -> a && b ).get() ) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "LNodeType at line " + lNodeType.getLineNumber() + " does not contain all mandatory DO from class " + lNodeType.getLnClass(),
+                    new Object[] { lNodeType } ));
+            res = false;
+        }
+        return res;
+    }
+
+    private boolean checkCompulsory( LNodeType lNodeType, DataObject dataObject, HashSet< String > checkedDO, DiagnosticChain diagnostics ) {
+        switch( dataObject.getPresCond() ) {
+        case "M":
+            if( ! checkedDO.contains( dataObject.getName() ) ) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "DO " + dataObject.getName() + " is missing in LN at line " + lNodeType.getLineNumber(),
+                        new Object[] { lNodeType } ));
+                return false;
+            }
+            break;
+        default:
+            AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: AnyLNValidator.checkCompulsory( " + dataObject.getPresCond() + " )" );
+            break;
+        }
+        return true;
+    }
+
+    private boolean updateCompulsory( DO do_, HashSet< String > checkedDO, DiagnosticChain diagnostics ) {
+        switch( doMap.get( do_.getName() ).getPresCond() ) {
+        case "M":
+        case "O":
+            if( checkedDO.contains( do_.getName() )) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "DO " + do_ + " cannot appear more than once in LN at line " + do_.getParentLNodeType().getLineNumber(),
+                        new Object[] { do_ } ));
+                return false;
+            }
+            checkedDO.add( do_.getName() );
+            break;
+        case "F":
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "DO " + do_ + " is forbidden in LN at line " + do_.getParentLNodeType().getLineNumber(),
+                    new Object[] { do_ } ));
+            return false;
+        default:
+            AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: AnyLNValidator.updateCompulsory( " + doMap.get( do_.getName() ).getPresCond() + " )" );
+            break;
+        }
+        return true;
+    }
+
+    private boolean validateDO( DO do_, DiagnosticChain diagnostics ) {
+
+        AbstractRiseClipseConsole.getConsole().verbose( "found DO " + do_.getName() + " in LNClass " + lnClass );
+
+        // DOIValidator validates DOI content
+        String cdc = doMap.get( do_.getName() ).getRefersToCDC().getName();
+        return cdcMap.get( cdc ).validateDO( do_, diagnostics );
+    }
+
+}
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java
index 82f1af1e4d6ba1527dbc30401a17fd8a3dced188..730555c3790a24535bea17ea002965e6cb0dbf11 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java
@@ -31,33 +31,49 @@ import org.eclipse.emf.ecore.EValidator;
 import fr.centralesupelec.edf.riseclipse.iec61850.nsd.LNClass;
 import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceSetImpl;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.AnyLN;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.util.SclSwitch;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
 import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
 
 public class NsdEObjectValidator implements EValidator {
 
     private NsdResourceSetImpl nsdResourceSet;
-    private HashMap< String, AnyLNValidator > lnMap;
+    private HashMap< String, AnyLNValidator > anyLNValidatorMap;
+    private HashMap<String,LNodeTypeValidator> lNodeTypeValidatorMap;
 
     public NsdEObjectValidator( NsdResourceSetImpl nsdResourceSet ) {
         this.nsdResourceSet = nsdResourceSet;
     }
 
     public void initializeValidationData() {
-        this.lnMap = this.nsdResourceSet.getLNClassStream()
-                .map( lnClass -> generateValidators( lnClass ) )
+        this.anyLNValidatorMap = this.nsdResourceSet.getLNClassStream()
+                .map( lnClass -> generateAnyLNValidators( lnClass ) )
+                .reduce( ( a, b ) -> {
+                    a.putAll( b );
+                    return a;
+                } ).get();
+
+        this.lNodeTypeValidatorMap = this.nsdResourceSet.getLNClassStream()
+                .map( lnClass -> generateLNodeTypeValidators( lnClass ) )
                 .reduce( ( a, b ) -> {
                     a.putAll( b );
                     return a;
                 } ).get();
     }
 
-    private HashMap< String, AnyLNValidator > generateValidators( LNClass lnClass ) {
+    private HashMap< String, AnyLNValidator > generateAnyLNValidators( LNClass lnClass ) {
         HashMap< String, AnyLNValidator > lnMap = new HashMap<>();
         lnMap.put( lnClass.getName(), new AnyLNValidator( lnClass ));
         return lnMap;
     }
 
+    private HashMap< String, LNodeTypeValidator > generateLNodeTypeValidators( LNClass lnClass ) {
+        HashMap< String, LNodeTypeValidator > lNodeTypeMap = new HashMap<>();
+        lNodeTypeMap.put( lnClass.getName(), new LNodeTypeValidator( lnClass ));
+        return lNodeTypeMap;
+    }
+
     @Override
     public boolean validate( EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) {
         return validate( eObject.eClass(), eObject, diagnostics, context );
@@ -66,19 +82,31 @@ public class NsdEObjectValidator implements EValidator {
     @Override
     public boolean validate( EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) {
 
-        if( this.lnMap == null ) {
+        if( this.anyLNValidatorMap == null ) {
             this.initializeValidationData();
         }
-
-        switch( eClass.getName() ) {
-        case "LN0":
-        case "LN":
-            AnyLN ln = ( AnyLN ) eObject;
-            return validateLN( ln, diagnostics );
-        default:
-            AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: NsdEObjectValidator.validate( " + eClass.getName() + " )" );
-            return false;
-        }
+        
+        SclSwitch< Boolean > sw = new SclSwitch< Boolean >() {
+
+            @Override
+            public Boolean caseAnyLN( AnyLN anyLN ) {
+                return validateAnyLN( anyLN, diagnostics );
+            }
+
+            @Override
+            public Boolean caseLNodeType( LNodeType lNodeType ) {
+                return validateLNodeType( lNodeType, diagnostics );
+            }
+
+            @Override
+            public Boolean defaultCase( EObject object ) {
+                AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: NsdEObjectValidator.validate( " + object.eClass().getName() + " )" );
+                return true;
+            }
+            
+        };
+
+        return sw.doSwitch( eObject );
     }
 
     @Override
@@ -90,12 +118,12 @@ public class NsdEObjectValidator implements EValidator {
         return true;
     }
 
-    private boolean validateLN( AnyLN ln, DiagnosticChain diagnostics ) {
+    private boolean validateAnyLN( AnyLN ln, DiagnosticChain diagnostics ) {
         AbstractRiseClipseConsole.getConsole().verbose( "" );
         AbstractRiseClipseConsole.getConsole().verbose( "NsdEObjectValidator.validateLN( " + ln.getLnClass() + " )" );
 
         // Check that LN has valid LNClass
-        if( ! this.lnMap.containsKey( ln.getLnClass() )) {
+        if( ! this.anyLNValidatorMap.containsKey( ln.getLnClass() )) {
             diagnostics.add( new BasicDiagnostic(
                     Diagnostic.ERROR,
                     RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
@@ -107,7 +135,27 @@ public class NsdEObjectValidator implements EValidator {
         AbstractRiseClipseConsole.getConsole().verbose( "found LNClass " + ln.getLnClass() + " in NSD files for LN at line " + ln.getLineNumber() );
 
         // AnyLNValidator validates LN content
-        return lnMap.get( ln.getLnClass() ).validateLN( ln, diagnostics );
+        return anyLNValidatorMap.get( ln.getLnClass() ).validateLN( ln, diagnostics );
+    }
+
+    protected Boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) {
+        AbstractRiseClipseConsole.getConsole().verbose( "" );
+        AbstractRiseClipseConsole.getConsole().verbose( "NsdEObjectValidator.validateLNodeType( " + lNodeType.getLnClass() + " )" );
+
+        // Check that LN has valid LNClass
+        if( ! this.anyLNValidatorMap.containsKey( lNodeType.getLnClass() )) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "LNClass " + lNodeType.getLnClass() + " not found in NSD files for LN at line " + lNodeType.getLineNumber(),
+                    new Object[] { lNodeType } ));
+            return false;
+        }
+        AbstractRiseClipseConsole.getConsole().verbose( "found LNClass " + lNodeType.getLnClass() + " in NSD files for LN at line " + lNodeType.getLineNumber() );
+
+        // AnyLNValidator validates LN content
+        return lNodeTypeValidatorMap.get( lNodeType.getLnClass() ).validateLNodeType( lNodeType, diagnostics );
     }
 
 }