From c56fb3afeded935341bbfd713ec76caa3192eff5 Mon Sep 17 00:00:00 2001
From: Dominique Marcadet <Dominique.Marcadet@centralesupelec.fr>
Date: Tue, 28 May 2019 17:03:25 +0200
Subject: [PATCH] create superclass GenericPresenceCondiitonValidator

to avoid much of duplicated code.
Not yet done for DataObjectPresenceCondiitonValidator.
---
 .../scl/validator/nsd/BasicTypeValidator.java |    1 -
 .../scl/validator/nsd/CDCValidator.java       |   11 +-
 .../nsd/ConstructedAttributeValidator.java    |    9 +-
 ...taAttributePresenceConditionValidator.java | 1435 ++--------------
 .../validator/nsd/EnumerationValidator.java   |    7 +-
 .../GenericPresenceConditionValidator.java    | 1334 +++++++++++++++
 .../scl/validator/nsd/LNClassValidator.java   |    7 +-
 ...taAttributePresenceConditionValidator.java | 1351 +--------------
 ...bDataObjectPresenceConditionValidator.java | 1448 +----------------
 9 files changed, 1588 insertions(+), 4015 deletions(-)
 create mode 100644 fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java

diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java
index a128e72..4530e67 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java
@@ -18,7 +18,6 @@
  */
 package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd;
 
-import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java
index f57a6dc..58a5a15 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java
@@ -45,11 +45,12 @@ public class CDCValidator {
         .forEach( cdc -> validators.put( cdc.getName(), new CDCValidator( cdc )));
     }
 
+    private static HashSet< String > validatedDOType = new HashSet<>(); 
+
     private DataAttributePresenceConditionValidator dataAttributePresenceConditionValidator;
     private SubDataObjectPresenceConditionValidator subDataObjectPresenceConditionValidator;
     private HashMap< String, TypeValidator > dataAttributeValidatorMap = new HashMap<>();
     private HashMap< String, CDCValidator > subDataObjectValidatorMap = new HashMap<>();
-    private HashSet< DOType > validatedDOType = new HashSet<>(); 
 
     private CDCValidator( CDC cdc ) {
         dataAttributePresenceConditionValidator = DataAttributePresenceConditionValidator.get( cdc );
@@ -78,15 +79,15 @@ public class CDCValidator {
     }
 
     public boolean validateDOType( DOType doType, DiagnosticChain diagnostics ) {
-        if( validatedDOType.contains( doType )) return true;
+        if( validatedDOType.contains( doType.getId() )) return true;
         AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] CDCValidator.validateDOType( " + doType.getId() + " ) at line " + doType.getLineNumber() );
-        validatedDOType.add( doType );
+        validatedDOType.add( doType.getId() );
         
         dataAttributePresenceConditionValidator.reset();
         doType
         .getDA()
         .stream()
-        .forEach( d -> dataAttributePresenceConditionValidator.addDA( d, diagnostics ));
+        .forEach( d -> dataAttributePresenceConditionValidator.addModelData( d, d.getName(), diagnostics ));
       
         boolean res = dataAttributePresenceConditionValidator.validate( doType, diagnostics );
         
@@ -94,7 +95,7 @@ public class CDCValidator {
         doType
         .getSDO()
         .stream()
-        .forEach( d -> subDataObjectPresenceConditionValidator.addSDO( d, diagnostics ));
+        .forEach( d -> subDataObjectPresenceConditionValidator.addModelData( d, d.getName(), diagnostics ));
         
         res = subDataObjectPresenceConditionValidator.validate( doType, diagnostics ) && res;
         
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java
index 1cdbe9d..90958ea 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java
@@ -32,9 +32,10 @@ import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
 
 public class ConstructedAttributeValidator extends TypeValidator {
 
+    private static HashSet< String > validatedDAType = new HashSet<>(); 
+
     private SubDataAttributePresenceConditionValidator subDataAttributePresenceConditionValidator;
     private HashMap< String, TypeValidator > subDataAttributeValidatorMap = new HashMap<>();
-    private HashSet< DAType > validatedDAType = new HashSet<>(); 
 
     public ConstructedAttributeValidator( ConstructedAttribute contructedAttribute ) {
         subDataAttributePresenceConditionValidator = SubDataAttributePresenceConditionValidator.get( contructedAttribute );
@@ -62,15 +63,15 @@ public class ConstructedAttributeValidator extends TypeValidator {
     }
 
     private boolean validateDAType( DAType daType, DiagnosticChain diagnostics ) {
-        if( validatedDAType.contains( daType )) return true;
+        if( validatedDAType.contains( daType.getId() )) return true;
         AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] ConstructedAttributeValidator.validateDAType( " + daType.getId() + " ) at line " + daType.getLineNumber() );
-        validatedDAType.add( daType );
+        validatedDAType.add( daType.getId() );
         
         subDataAttributePresenceConditionValidator.reset();
         daType
         .getBDA()
         .stream()
-        .forEach( bda -> subDataAttributePresenceConditionValidator.addBDA( bda, diagnostics ));
+        .forEach( bda -> subDataAttributePresenceConditionValidator.addModelData( bda, bda.getName(), diagnostics ));
       
         boolean res = subDataAttributePresenceConditionValidator.validate( daType, diagnostics );
         
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java
index 1e18a8d..3df5165 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java
@@ -19,14 +19,12 @@
 package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd;
 
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map.Entry;
 
-import org.apache.commons.lang3.tuple.Pair;
 import org.eclipse.emf.common.util.BasicDiagnostic;
 import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.common.util.DiagnosticChain;
 import org.eclipse.emf.common.util.EList;
+import org.eclipse.jdt.annotation.Nullable;
 
 import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataObject;
@@ -34,11 +32,9 @@ import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
-import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
-import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole;
 
-public class DataAttributePresenceConditionValidator {
-    
+public class DataAttributePresenceConditionValidator extends GenericPresenceConditionValidator< CDC, DOType, @Nullable DA >{
+
     private static HashMap< String, DataAttributePresenceConditionValidator > validators = new HashMap<>();
     
     public static DataAttributePresenceConditionValidator get( CDC cdc ) {
@@ -49,1373 +45,136 @@ public class DataAttributePresenceConditionValidator {
     }
     
     private CDC cdc;
-    
-    // Name of the DataAttribute/DA, DA
-    private HashMap< String, DA > presentDA = new HashMap<>();
-    
-    private HashSet< String > mandatory;
-    private HashSet< String > optional;
-    private HashSet< String > forbidden;
-    private HashSet< String > notApplicable;
-    private HashSet< String > mandatoryMulti;
-    private HashSet< String > optionalMulti;
-    private HashMap< Integer, HashSet< String > > atLeastOne;
-    private HashSet< String > atMostOne;
-    private HashMap< Integer, HashSet< String > > allOrNonePerGroup;
-    private HashMap< Integer, HashSet< String > > allOnlyOneGroup;
-    private HashMap< Integer, HashSet< String > > allAtLeastOneGroup;
-    private HashMap< String, String > mandatoryIfSiblingPresentElseForbidden;
-    private HashMap< String, String > mandatoryIfSiblingPresentElseOptional;
-    private HashMap< String, String > optionalIfSiblingPresentElseMandatory;
-    private HashMap< String, String > forbiddenIfSiblingPresentElseMandatory;
-    private HashMap< String, String > mandatoryIfTextConditionElseOptional;
-    private HashMap< String, String > mandatoryIfTextConditionElseForbidden;
-    private HashMap< String, String > optionalIfTextConditionElseForbidden;
-    private HashMap< String, Pair< Integer, Integer > > mandatoryMultiRange;
-    private HashMap< String, Pair< Integer, Integer > > optionalMultiRange;
-    private HashSet< String > mandatoryIfSubstitutionElseForbidden;
-    private HashSet< String > mandatoryInLLN0ElseOptional;
-    private HashSet< String > mandatoryInLLN0ElseForbidden;
-    private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional;
-    private HashSet< String > mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional;
-    private HashSet< String > mandatoryIfAnalogValueIncludesIElseForbidden;
-    private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden;
-    private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden;
-    private HashSet< String > mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional;
-    private HashSet< String > mandatoryInRootLogicalDeviceElseOptional;
-    private HashSet< String > mandatoryIfControlSupportsTimeElseOptional;
-    private HashMap< String, String > oneOrMoreIfSiblingPresentElseForbidden;
-    private HashSet< String > mandatoryIfControlSupportsSecurity1ElseOptional;
-    private HashSet< String > mandatoryIfControlSupportsSecurity2ElseOptional;
-    private HashMap< String, String > optionalIfSiblingPresentElseForbidden;
-    private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2;
-    private HashSet< String > mandatoryIfMeasuredValueExposesRange;
-    private HashSet< String > optionalIfPhsRefIsSynchrophasorElseMandatory;
-    
-    private final IRiseClipseConsole console = AbstractRiseClipseConsole.getConsole();
-    
+
     public DataAttributePresenceConditionValidator( CDC cdc ) {
-        this.cdc = cdc;
+        super( cdc );
         
+        this.cdc = cdc;
+    }
+
+    @Override
+    protected void createSpecifications( CDC cdc ) {
         cdc
         .getDataAttribute()
         .stream()
-        .forEach( da -> addSpecification( da.getName(), da.getPresCond(), da.getPresCondArgs() ) );
+        .forEach( da -> addSpecification( da.getName(), da.getPresCond(), da.getPresCondArgs(), da.getRefersToPresCondArgsDoc() ));
+    }
 
-        checkSpecification();
+    @Override
+    protected String getPresenceConditionValidatorName() {
+        return "DataAttributePresenceConditionValidator";
     }
-    
-    public void reset() {
-        for( String da : presentDA.keySet() ) {
-            presentDA.put( da, null );
-        }
+
+    @Override
+    protected String getNsdModelName() {
+        return cdc.getName();
     }
-    
-    private void addSpecification( String name, String presCond, String presCondArgs ) {
-        if( presentDA.containsKey( name )) {
-            console.warning( "[NSD setup] " + name + " has already been added to DataAttributePresenceConditionValidator" );
-            return;
-        }
-        presentDA.put( name, null );
 
-        switch( presCond ) {
-        case "M" :
-            // Element is mandatory
-            if( mandatory == null ) mandatory = new HashSet<>();
-            mandatory.add( name );
-            break;
-        case "O" :
-            // Element is optional
-            if( optional == null ) optional = new HashSet<>();
-            optional.add( name );
-            break;
-        case "F" :
-            // Element is forbidden
-            if( forbidden == null ) forbidden = new HashSet<>();
-            forbidden.add( name );
-            break;
-        case "na" :
-            // Element is not applicable
-            // -> TODO: what does it mean ? what do we have to check ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"na\" in PresenceCondition" );
-            if( notApplicable == null ) notApplicable = new HashSet<>();
-            notApplicable.add( name );
-            break;
-        case "Mmulti" :
-            // At least one element shall be present; all instances have an instance number > 0
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"Mmulti\" in PresenceCondition" );
-            if( mandatoryMulti == null ) mandatoryMulti = new HashSet<>();
-            mandatoryMulti.add( name );
-            break;
-        case "Omulti" :
-            // Zero or more elements may be present; all instances have an instance number > 0
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"Omulti\" in PresenceCondition" );
-            if( optionalMulti == null ) optionalMulti = new HashSet<>();
-            optionalMulti.add( name );
-            break;
-        case "AtLeastOne" :
-            // Parameter n: group number (> 0).
-            // At least one of marked elements of a group n shall be present
-            if( atLeastOne == null ) atLeastOne = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not a positive integer" );
-                    break;
-                }
-                if( ! atLeastOne.containsKey( arg )) {
-                    atLeastOne.put( arg, new HashSet<>() );
-                }
-                atLeastOne.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not an integer" );
-                break;
-            }
-        case "AtMostOne" :
-            // At most one of marked elements shall be present
-            if( atMostOne == null ) atMostOne = new HashSet<>();
-            atMostOne.add( name );
-            break;
-        case "AllOrNonePerGroup" :
-            // Parameter n: group number (> 0).
-            // All or none of the elements of a group n shall be present
-            if( allOrNonePerGroup == null ) allOrNonePerGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allOrNonePerGroup.containsKey( arg )) {
-                    allOrNonePerGroup.put( arg, new HashSet<>() );
-                }
-                allOrNonePerGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not an integer" );
-                break;
-            }
-        case "AllOnlyOneGroup" :
-            // Parameter n: group number (> 0).
-            // All elements of only one group n shall be present
-            if( allOnlyOneGroup == null ) allOnlyOneGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allOnlyOneGroup.containsKey( arg )) {
-                    allOnlyOneGroup.put( arg, new HashSet<>() );
-                }
-                allOnlyOneGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not an integer" );
-                break;
-            }
-        case "AllAtLeastOneGroup" :
-            // Parameter n: group number (> 0).
-            // All elements of at least one group n shall be present
-            if( allAtLeastOneGroup == null ) allAtLeastOneGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allAtLeastOneGroup.containsKey( arg )) {
-                    allAtLeastOneGroup.put( arg, new HashSet<>() );
-                }
-                allAtLeastOneGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not an integer" );
-                break;
-            }
-        case "MF" :
-            // Parameter sibling: sibling element name.
-            // Mandatory if sibling element is present, otherwise forbidden
-            if( mandatoryIfSiblingPresentElseForbidden == null ) mandatoryIfSiblingPresentElseForbidden = new HashMap<>();
-            mandatoryIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MO" :
-            // Parameter sibling: sibling element name.
-            // Mandatory if sibling element is present, otherwise optional
-            if( mandatoryIfSiblingPresentElseOptional == null ) mandatoryIfSiblingPresentElseOptional = new HashMap<>();
-            mandatoryIfSiblingPresentElseOptional.put( name, presCondArgs );
-            break;
-        case "OM" :
-            // Parameter sibling: sibling element name.
-            // Optional if sibling element is present, otherwise mandatory
-            if( optionalIfSiblingPresentElseMandatory == null ) optionalIfSiblingPresentElseMandatory = new HashMap<>();
-            optionalIfSiblingPresentElseMandatory.put( name, presCondArgs );
-            break;
-        case "FM" :
-            // Parameter sibling: sibling element name.
-            // Forbidden if sibling element is present, otherwise mandatory
-            if( forbiddenIfSiblingPresentElseMandatory == null ) forbiddenIfSiblingPresentElseMandatory = new HashMap<>();
-            forbiddenIfSiblingPresentElseMandatory.put( name, presCondArgs );
-            break;
-        case "MOcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is mandatory, otherwise optional
-            if( mandatoryIfTextConditionElseOptional == null ) mandatoryIfTextConditionElseOptional = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not a positive integer" );
-                    break;
-                }
-                mandatoryIfTextConditionElseOptional.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not an integer" );
-                break;
-            }
-        case "MFcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is mandatory, otherwise forbidden
-            if( mandatoryIfTextConditionElseForbidden == null ) mandatoryIfTextConditionElseForbidden = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
-                    break;
-                }
-                mandatoryIfTextConditionElseForbidden.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
-                break;
-            }
-        case "OFcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is optional, otherwise forbidden
-            if( optionalIfTextConditionElseForbidden == null ) optionalIfTextConditionElseForbidden = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
-                    break;
-                }
-                optionalIfTextConditionElseForbidden.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
-                break;
-            }
-        case "MmultiRange" :
-            // Parameters min, max: limits for instance number (> 0).
-            // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MmultiRange\" in PresenceCondition" );
-            if( mandatoryMultiRange == null ) mandatoryMultiRange = new HashMap<>();
-            String[] limits1 = presCondArgs.split( "[ ,]+" );
-            if( limits1.length != 2 ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MmultiRange\" is not two integers" );
-                break;
-            }
-            Integer min1 = Integer.valueOf( limits1[0] );
-            if( min1 <= 0 ) {
-                console.warning( "[NSD setup] first argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
-                break;
-            }
-            Integer max1 = Integer.valueOf( limits1[1] );
-            if( max1 <= 0 ) {
-                console.warning( "[NSD setup] second argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
-                break;
-            }
-            mandatoryMultiRange.put( name, Pair.of( min1, max1 ));
-            break;
-        case "OmultiRange" :
-            // Parameters min, max: limits for instance number (> 0).
-            // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"OmultiRange\" in PresenceCondition" );
-            if( optionalMultiRange == null ) optionalMultiRange = new HashMap<>();
-            String[] limits2 = presCondArgs.split( "[ ,]+" );
-            if( limits2.length != 2 ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"OmultiRange\" is not two integers" );
-                break;
-            }
-            Integer min2 = Integer.valueOf( limits2[0] );
-            if( min2 <= 0 ) {
-                console.warning( "[NSD setup] first argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
-                break;
-            }
-            Integer max2 = Integer.valueOf( limits2[1] );
-            if( max2 <= 0 ) {
-                console.warning( "[NSD setup] second argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
-                break;
-            }
-            optionalMultiRange.put( name, Pair.of( min2, max2 ));
-            break;
-        case "MFsubst" :
-            // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
-            // TODO: how do we know if substitution is supported ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MFsubst\" in PresenceCondition" );
-            if( mandatoryIfSubstitutionElseForbidden == null ) mandatoryIfSubstitutionElseForbidden = new HashSet<>();
-            mandatoryIfSubstitutionElseForbidden.add( name );
-            break;
-        case "MOln0" :
-            // Element is mandatory in the context of LLN0; otherwise optional
-            if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>();
-            mandatoryInLLN0ElseOptional.add( name );
-            break;
-        case "MFln0" :
-            // Element is mandatory in the context of LLN0; otherwise forbidden
-            if( mandatoryInLLN0ElseForbidden == null ) mandatoryInLLN0ElseForbidden = new HashSet<>();
-            mandatoryInLLN0ElseForbidden.add( name );
-            break;
-        case "MOlnNs" :
-            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOlnNs\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional = new HashSet<>();
-            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional.add( name );
-            break;
-        case "MOdataNs" :
-            // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
-            // otherwise optional. See IEC 61850-7-1 for use of name space
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOdataNs\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional == null ) mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional = new HashSet<>();
-            mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional.add( name );
-            break;
-        case "MFscaledAV" :
-            // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
-            // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
-            // the description of scaling remains mandatory for their (SCL) configuration
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MFscaledAV\" in PresenceCondition" );
-            if( mandatoryIfAnalogValueIncludesIElseForbidden == null ) mandatoryIfAnalogValueIncludesIElseForbidden = new HashSet<>();
-            mandatoryIfAnalogValueIncludesIElseForbidden.add( name );
-            break;
-        case "MFscaledMagV" :
-            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
-            // *See MFscaledAV
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MFscaledMagV\" in PresenceCondition" );
-            if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden = new HashSet<>();
-            mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden.add( name );
-            break;
-        case "MFscaledAngV" :
-            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
-            // *See MFscaledAV
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MFscaledAngV\" in PresenceCondition" );
-            if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden = new HashSet<>();
-            mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden.add( name );
-            break;
-        case "MOrms" :
-            // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
-            // (value of data attribute 'hvRef' is 'rms'), optional otherwise
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOrms\" in PresenceCondition" );
-            if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional == null ) mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional = new HashSet<>();
-            mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional.add( name );
-            break;
-        case "MOrootLD" :
-            // Element is mandatory in the context of a root logical device; otherwise it is optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOrootLD\" in PresenceCondition" );
-            if( mandatoryInRootLogicalDeviceElseOptional == null ) mandatoryInRootLogicalDeviceElseOptional = new HashSet<>();
-            mandatoryInRootLogicalDeviceElseOptional.add( name );
-            break;
-        case "MOoperTm" :
-            // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOoperTm\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsTimeElseOptional == null ) mandatoryIfControlSupportsTimeElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsTimeElseOptional.add( name );
-            break;
-        case "MmultiF" :
-            // Parameter sibling: sibling element name.
-            // One or more elements must be present if sibling element is present, otherwise forbidden
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MmultiF\" in PresenceCondition" );
-            if( oneOrMoreIfSiblingPresentElseForbidden == null ) oneOrMoreIfSiblingPresentElseForbidden = new HashMap<>();
-            oneOrMoreIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MOsbo" :
-            // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
-            // otherwise optional and value is of no impact
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOsbo\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsSecurity1ElseOptional == null ) mandatoryIfControlSupportsSecurity1ElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsSecurity1ElseOptional.add( name );
-            break;
-        case "MOenhanced" :
-            // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
-            // otherwise optional and value is of no impact
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MOenhanced\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsSecurity2ElseOptional == null ) mandatoryIfControlSupportsSecurity2ElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsSecurity2ElseOptional.add( name );
-            break;
-        case "MONamPlt" :
-            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-            // TODO: same as "MOlnNs" ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MONamPlt\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 = new HashSet<>();
-            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2.add( name );
-            break;
-        case "OF" :
-            // Parameter sibling: sibling element name.
-            // Optional if sibling element is present, otherwise forbidden
-            if( optionalIfSiblingPresentElseForbidden == null ) optionalIfSiblingPresentElseForbidden = new HashMap<>();
-            optionalIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MORange" :
-            // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
-            // (with the attribute range respectively rangeAng)
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"MORange\" in PresenceCondition" );
-            if( mandatoryIfMeasuredValueExposesRange == null ) mandatoryIfMeasuredValueExposesRange = new HashSet<>();
-            mandatoryIfMeasuredValueExposesRange.add( name );
-            break;
-        case "OMSynPh" :
-            // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
-            console.warning( "[NSD setup] NOT IMPLEMENTED: DataAttribute " + name + " declared as \"OMSynPh\" in PresenceCondition" );
-            if( optionalIfPhsRefIsSynchrophasorElseMandatory == null ) optionalIfPhsRefIsSynchrophasorElseMandatory = new HashSet<>();
-            optionalIfPhsRefIsSynchrophasorElseMandatory.add( name );
-            break;
-        default:
-            console.warning( "[NSD setup] the PresenceCondition " + presCond + " of AnyLNClass " + name + " is unknown" );
-            break;
-        }
-        
+    @Override
+    protected String getNsdModelClassName() {
+        return "CDC";
     }
-    
-    private void checkSpecification() {
-        // TODO: do we have to check the presence of the sibling in inherited AbstractLNClass ?
-        if( mandatoryIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( mandatoryIfSiblingPresentElseOptional != null ) {
-            for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
-                if( ! presentDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( optionalIfSiblingPresentElseMandatory != null ) {
-            for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) {
-                if( ! presentDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( forbiddenIfSiblingPresentElseMandatory != null ) {
-            for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
-                if( ! presentDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( optionalIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
+
+    @Override
+    protected String getNsdComponentClassName() {
+        return "DataAttribute";
     }
 
-    public boolean addDA( DA da, DiagnosticChain diagnostics ) {
-        if( ! presentDA.containsKey( da.getName() )) {
-            diagnostics.add( new BasicDiagnostic(
-                    Diagnostic.ERROR,
-                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                    0,
-                    "[NSD validation] DA " + da.getName() + " in DOType (line " + da.getParentDOType().getLineNumber() + ") not found in CDC " + cdc.getName(),
-                    new Object[] { da } ));
-            return false;
-        }
+    @Override
+    protected String getSclModelClassName() {
+        return "DOType";
+    }
 
-        if( presentDA.get( da.getName() ) != null ) {
-            diagnostics.add( new BasicDiagnostic(
-                    Diagnostic.ERROR,
-                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                    0,
-                    "[NSD validation] DA " + da.getName() + " in DOType (line " + da.getParentDOType().getLineNumber() + ") already present in CDC " + cdc.getName(),
-                    new Object[] { da } ));
-            return false;
-        }
-        presentDA.put( da.getName(), da );
-        return true;
+    @Override
+    protected String getSclComponentClassName() {
+        return "DA";
     }
-    
-    public boolean validate( DOType doType, DiagnosticChain diagnostics ) {
-        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] DataAttributePresenceConditionValidator.validate(id=" + doType.getId() + ") at line " + doType.getLineNumber() );
 
+    @Override
+    protected boolean validateMFln0( DOType sclModel, DiagnosticChain diagnostics ) {
         boolean res = true;
-        
-        // presCond: "M"
-        // Element is mandatory
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
-        if( mandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"M\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( String name : this.mandatory ) {
-                if( presentDA.get( name ) == null ) {
-                  diagnostics.add( new BasicDiagnostic(
-                          Diagnostic.ERROR,
-                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                          0,
-                          "[NSD validation] DA " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                          new Object[] { doType } ));
-                  res = false;
-                }
-            }
-        }
-
-        // presCond: "O"
-        // Element is optional
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
-        if( optional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"O\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( String name : this.optional ) {
-                if( presentDA.get( name ) == null ) {
-                    // Nothing
-                }
-            }
-        }
-
-        // presCond: "F"
-        // Element is forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( forbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"F\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( String name : this.forbidden ) {
-                if( presentDA.get( name ) != null ) {
-                  diagnostics.add( new BasicDiagnostic(
-                          Diagnostic.ERROR,
-                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                          0,
-                          "[NSD validation] DA " + name + " is forbidden in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                          new Object[] { doType } ));
-                  res = false;
-                }
-            }
-        }
-
-        // presCond: "na"
-        // Element is not applicable
-        // Usage in standard NSD files (version 2007B): only for dsPresCond
-        // -> TODO: what does it mean ? what do we have to check ?
-        if( notApplicable != null ) {
-            for( String name : notApplicable ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"na\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-        
-        // presCond: "Mmulti"
-        // At least one element shall be present; all instances have an instance number > 0
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryMulti != null ) {
-            for( String name : mandatoryMulti ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"Mmulti\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "Omulti"
-        // Zero or more elements may be present; all instances have an instance number > 0
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalMulti != null ) {
-            for( String name : optionalMulti ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"Omulti\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-        
-        // presCond: "AtLeastOne"
-        // Parameter n: group number (> 0).
-        // At least one of marked elements of a group n shall be present
-        // Usage in standard NSD files (version 2007B): DataObject and SubDataObject and DataAttribute and SubDataAttribute
-        if( atLeastOne != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtLeastOne\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) {
-                boolean groupOK = false;
-                for( String member : e1.getValue() ) {
-                    if( presentDA.get( member ) != null ) {
-                        groupOK = true;
-                        break;
-                    }
-                }
-                if( ! groupOK ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has no elements in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                    res = false;
-                }
-            }
-        }
-        
-        // presCond: "AtMostOne" :
-        // At most one of marked elements shall be present
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( atMostOne != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtMostOne\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            int count = 0;
-            for( String s : atMostOne ) {
-                if( presentDA.get( s ) != null ) {
-                    ++count;
-                }
-            }
-            if( count > 1 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] LNodeType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has more than one element marked AtMostOne",
-                        new Object[] { doType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "AllOrNonePerGroup" :
-        // Parameter n: group number (> 0).
-        // All or none of the elements of a group n shall be present
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( allOrNonePerGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOrNonePerGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentDA.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                    res = false;
-                }
-            }
-        }
-        
-        // presCond: "AllOnlyOneGroup" :
-        // Parameter n: group number (> 0).
-        // All elements of only one group n shall be present
-        // Usage in standard NSD files (version 2007B): DataObject and SubDataAttribute
-        if( allOnlyOneGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOnlyOneGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            int groupNumber = 0;
-            for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentDA.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                    res = false;
-                }
-                else if( groupCount > 0 ) {
-                    if( groupNumber == 0 ) {
-                        groupNumber = e1.getKey();
-                    }
-                    else {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] LNodeType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has several groups with all elements",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-            if( groupNumber == 0 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements",
-                        new Object[] { doType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "AllAtLeastOneGroup" :
-        // Parameter n: group number (> 0).
-        // All elements of at least one group n shall be present
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( allAtLeastOneGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllAtLeastOneGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            int groupNumber = 0;
-            for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentDA.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if( groupCount == e1.getValue().size() ) {
-                    groupNumber = e1.getKey();
-                }
-            }
-            if( groupNumber == 0 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements",
-                        new Object[] { doType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "MF" :
-        // Parameter sibling: sibling element name.
-        // Mandatory if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfSiblingPresentElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MF\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
-                if( presentDA.get( entry.getValue() ) != null ) {
-                    if( presentDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-                else {
-                    if( presentDA.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "MO" :
-        // Parameter sibling: sibling element name.
-        // Mandatory if sibling element is present, otherwise optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryIfSiblingPresentElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MO\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
-                if( presentDA.get( entry.getValue() ) != null ) {
-                    if( presentDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { doType } ));
-                        res = false;
+        EList< AbstractDataObject > adoList = sclModel.getReferredByAbstractDataObject();
+        for( AbstractDataObject ado : adoList ) {
+            if( ado instanceof DO ) {
+                DO do_ = ( DO ) ado;
+                if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) {
+                    for( String attribute : mandatoryInLLN0ElseOptional ) {
+                        DA da = presentSclComponent.get( attribute );
+                        if( da == null ) {
+                            diagnostics.add( new BasicDiagnostic(
+                                    Diagnostic.ERROR,
+                                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                    0,
+                                    "[NSD validation] " + getSclComponentClassName() + " " + attribute + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass LLN0",
+                                    new Object[] { sclModel } ));
+                            res = false;
+                        }
                     }
                 }
             }
-        }
-        
-        // presCond: "OM" :
-        // Parameter sibling: sibling element name.
-        // Optional if sibling element is present, otherwise mandatory
-        // Usage in standard NSD files (version 2007B): None
-        if( optionalIfSiblingPresentElseMandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OM\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) {
-                if( presentDA.get( entry.getValue() ) == null ) {
-                    if( presentDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
+            else {
+                // ado instanceof SDO
             }
         }
-        
-        // presCond: "FM" :
-        // Parameter sibling: sibling element name.
-        // Forbidden if sibling element is present, otherwise mandatory
-        // Usage in standard NSD files (version 2007B): None
-        if( forbiddenIfSiblingPresentElseMandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"FM\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
-                if( presentDA.get( entry.getValue() ) != null ) {
-                    if( presentDA.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { doType } ));
-                        res = false;
+        return res;
+    }
+
+    @Override
+    protected boolean validateMOln0( DOType sclModel, DiagnosticChain diagnostics ) {
+        boolean res = true;
+        EList< AbstractDataObject > adoList = sclModel.getReferredByAbstractDataObject();
+        for( AbstractDataObject ado : adoList ) {
+            if( ado instanceof DO ) {
+                DO do_ = ( DO ) ado;
+                if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) {
+                    for( String attribute : mandatoryInLLN0ElseForbidden ) {
+                        DA da = presentSclComponent.get( attribute );
+                        if( da == null ) {
+                            diagnostics.add( new BasicDiagnostic(
+                                    Diagnostic.ERROR,
+                                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                    0,
+                                    "[NSD validation] " + getSclComponentClassName() + " " + attribute + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass LLN0",
+                                    new Object[] { sclModel } ));
+                            res = false;
+                        }
                     }
                 }
                 else {
-                    if( presentDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
+                    for( String attribute : mandatoryInLLN0ElseForbidden ) {
+                        DA da = presentSclComponent.get( attribute );
+                        if( da != null ) {
+                            diagnostics.add( new BasicDiagnostic(
+                                    Diagnostic.ERROR,
+                                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                    0,
+                                    "[NSD validation] " + getSclComponentClassName() + " " + attribute + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + do_.getParentLNodeType().getLnClass(),
+                                    new Object[] { sclModel } ));
+                            res = false;
+                        }
                     }
                 }
             }
-        }
-        
-        // presCond: "MOcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is mandatory, otherwise optional
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfTextConditionElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOcond\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) {
-                String doc = cdc
-                        .getDataAttribute()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
-
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.WARNING,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC "
-                                + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is "
-                                + ( presentDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { doType } ));
+            else {
+                // ado instanceof SDO
             }
         }
-        
-        // presCond: "MFcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is mandatory, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfTextConditionElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFcond\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) {
-                String doc = cdc
-                        .getDataAttribute()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
-
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.WARNING,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC "
-                                + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
-                                + ( presentDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { doType } ));
-            }
-        }
-        
-        // presCond: "OFcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is optional, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalIfTextConditionElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OFcond\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) {
-                String doc = cdc
-                        .getDataAttribute()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
+        return res;
+    }
 
+    @Override
+    protected boolean validateOMSynPh( DOType sclModel, DiagnosticChain diagnostics ) {
+        for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) {
+            if( presentSclComponent.get( name ) != null ) {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] DA " + entry.getKey() + " is optional in DOType (line " + doType.getLineNumber() + ") with CDC "
-                                + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
-                                + ( presentDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { doType } ));
-            }
-        }
-        
-        // presCond: "MmultiRange" :
-        // Parameters min, max: limits for instance number (> 0).
-        // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-        // Usage in standard NSD files (version 2007B): None
-        if( mandatoryMultiRange != null ) {
-            for( String name : mandatoryMultiRange.keySet() ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MmultiRange\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "OmultiRange" :
-        // Parameters min, max: limits for instance number (> 0).
-        // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalMultiRange != null ) {
-            for( String name : optionalMultiRange.keySet() ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"OmultiRange\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFsubst" :
-        // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfSubstitutionElseForbidden != null ) {
-            for( String name : mandatoryIfSubstitutionElseForbidden ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFsubst\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
+                        "[NSD validation] verification of PresenceCondition \"OMSynPh\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                        new Object[] { sclModel } ));
             }
         }
-        
-        // presCond: "MOln0" :
-        // Element is mandatory in the context of LLN0; otherwise optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryInLLN0ElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject();
-            for( AbstractDataObject ado : adoList ) {
-                if( ado instanceof DO ) {
-                    DO do_ = ( DO ) ado;
-                    if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) {
-                        for( String attribute : mandatoryInLLN0ElseOptional ) {
-                            DA da = presentDA.get( attribute );
-                            if( da == null ) {
-                                diagnostics.add( new BasicDiagnostic(
-                                        Diagnostic.ERROR,
-                                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                        0,
-                                        "[NSD validation] DA " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0",
-                                        new Object[] { doType } ));
-                                res = false;
-                            }
-                        }
-                    }
-                }
-                else {
-                    // ado instanceof SDO
-                }
-            }
-        }
-        
-        // presCond: "MFln0" :
-        // Element is mandatory in the context of LLN0; otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryInLLN0ElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject();
-            for( AbstractDataObject ado : adoList ) {
-                if( ado instanceof DO ) {
-                    DO do_ = ( DO ) ado;
-                    if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) {
-                        for( String attribute : mandatoryInLLN0ElseForbidden ) {
-                            DA da = presentDA.get( attribute );
-                            if( da == null ) {
-                                diagnostics.add( new BasicDiagnostic(
-                                        Diagnostic.ERROR,
-                                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                        0,
-                                        "[NSD validation] DA " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0",
-                                        new Object[] { doType } ));
-                                res = false;
-                            }
-                        }
-                    }
-                    else {
-                        for( String attribute : mandatoryInLLN0ElseForbidden ) {
-                            DA da = presentDA.get( attribute );
-                            if( da != null ) {
-                                diagnostics.add( new BasicDiagnostic(
-                                        Diagnostic.ERROR,
-                                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                        0,
-                                        "[NSD validation] DA " + attribute + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " + do_.getParentLNodeType().getLnClass(),
-                                        new Object[] { doType } ));
-                                res = false;
-                            }
-                        }
-                    }
-                }
-                else {
-                    // ado instanceof SDO
-                }
-            }
-        }
-
-        // presCond: "MOlnNs" :
-        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO: The meaning is not clear.
-        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional != null ) {
-            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOlnNs\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOdataNs" :
-        // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
-        // otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO: The meaning is not clear.
-        if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional != null ) {
-            for( String name : mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOdataNs\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledAV" :
-        // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
-        // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
-        // the description of scaling remains mandatory for their (SCL) configuration
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfAnalogValueIncludesIElseForbidden != null ) {
-            for( String name : mandatoryIfAnalogValueIncludesIElseForbidden ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledMagV" :
-        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
-        // *See MFscaledAV
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden != null ) {
-            for( String name : mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledAngV" :
-        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
-        // *See MFscaledAV
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden != null ) {
-            for( String name : mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOrms" :
-        // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
-        // (value of data attribute 'hvRef' is 'rms'), optional otherwise
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional != null ) {
-            for( String name : mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOrms\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOrootLD" :
-        // Element is mandatory in the context of a root logical device; otherwise it is optional
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryInRootLogicalDeviceElseOptional != null ) {
-            for( String name : mandatoryInRootLogicalDeviceElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOrootLD\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOoperTm" :
-        // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsTimeElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsTimeElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOoperTm\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MmultiF" :
-        // Parameter sibling: sibling element name.
-        // One or more elements must be present if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        // TODO: One or more elements ? Is there an instance number ?
-        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
-            for( String name : oneOrMoreIfSiblingPresentElseForbidden.keySet() ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MmultiF\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOsbo" :
-        // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
-        // otherwise optional and value is of no impact
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsSecurity1ElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsSecurity1ElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOsbo\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOenhanced" :
-        // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
-        // otherwise optional and value is of no impact
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsSecurity2ElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsSecurity2ElseOptional ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOenhanced\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MONamPlt" :
-        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataObject
-        // TODO: same as "MOlnNs" ?
-        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 != null ) {
-            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MONamPlt\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "OF" :
-        // Parameter sibling: sibling element name.
-        // Optional if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute
-        if( optionalIfSiblingPresentElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OF\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) {
-                if( presentDA.get( entry.getValue() ) == null ) {
-                    if( presentDA.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] DA " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-
-        // presCond: "MORange" :
-        // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
-        // (with the attribute range respectively rangeAng)
-        // Usage in standard NSD files (version 2007B): SubDataAttribute
-        // TODO
-        if( mandatoryIfMeasuredValueExposesRange != null ) {
-            for( String name : mandatoryIfMeasuredValueExposesRange ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MORange\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "OMSynPh" :
-        // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
-        // Usage in standard NSD files (version 2007B): SubDataObject
-        // TODO
-        if( optionalIfPhsRefIsSynchrophasorElseMandatory != null ) {
-            for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) {
-                if( presentDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"OMSynPh\" for DA " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        return res;
+        return true;
     }
 
 }
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java
index 81a178d..803af2f 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java
@@ -37,11 +37,12 @@ import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
 
 public class EnumerationValidator extends TypeValidator {
     
+    private static HashSet< String > validatedEnumType = new HashSet<>();
+
     private HashMap< String, Integer > literals = new HashMap<>();
     private String name;
     private String inheritedFromName;
     private EnumerationValidator inheritedFrom;
-    private HashSet< EnumType > validatedEnumType = new HashSet<>();
 
     public EnumerationValidator( Enumeration enumeration ) {
         this.name = enumeration.getName();
@@ -139,9 +140,9 @@ public class EnumerationValidator extends TypeValidator {
     }
 
     public boolean validateEnumType( EnumType enumType, DiagnosticChain diagnostics ) {
-        if( validatedEnumType.contains( enumType )) return true;
+        if( validatedEnumType.contains( enumType.getId() )) return true;
         AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] EnumerationValidator.validateEnumType( " + enumType.getId() + " ) at line " + enumType.getLineNumber() );
-        validatedEnumType.add( enumType );
+        validatedEnumType.add( enumType.getId() );
         
         boolean res = true;
         
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java
new file mode 100644
index 0000000..ac41ef8
--- /dev/null
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java
@@ -0,0 +1,1334 @@
+/**
+ *  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 java.util.Map.Entry;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.Doc;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.NsdObject;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.SclObject;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
+import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
+import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole;
+
+public abstract class GenericPresenceConditionValidator< NsdModel extends NsdObject, SclModel extends SclObject, @Nullable SclComponent extends SclObject > {
+    
+    // Name of the NsdComponent/SclComponent, SclComponent
+    protected HashMap< String, SclComponent > presentSclComponent = new HashMap<>();
+    
+    protected HashSet< String > mandatory;
+    protected HashSet< String > optional;
+    protected HashSet< String > forbidden;
+    protected HashSet< String > notApplicable;
+    protected HashSet< String > mandatoryMulti;
+    protected HashSet< String > optionalMulti;
+    protected HashMap< Integer, HashSet< String > > atLeastOne;
+    protected HashSet< String > atMostOne;
+    protected HashMap< Integer, HashSet< String > > allOrNonePerGroup;
+    protected HashMap< Integer, HashSet< String > > allOnlyOneGroup;
+    protected HashMap< Integer, HashSet< String > > allAtLeastOneGroup;
+    protected HashMap< String, String > mandatoryIfSiblingPresentElseForbidden;
+    protected HashMap< String, String > mandatoryIfSiblingPresentElseOptional;
+    protected HashMap< String, String > optionalIfSiblingPresentElseMandatory;
+    protected HashMap< String, String > forbiddenIfSiblingPresentElseMandatory;
+    protected HashMap< String, String > mandatoryIfTextConditionElseOptional;
+    protected HashMap< String, String > mandatoryIfTextConditionElseOptionalDoc;
+    protected HashMap< String, String > mandatoryIfTextConditionElseForbidden;
+    protected HashMap< String, String > mandatoryIfTextConditionElseForbiddenDoc;
+    protected HashMap< String, String > optionalIfTextConditionElseForbidden;
+    protected HashMap< String, String > optionalIfTextConditionElseForbiddenDoc;
+    protected HashMap< String, Pair< Integer, Integer > > mandatoryMultiRange;
+    protected HashMap< String, Pair< Integer, Integer > > optionalMultiRange;
+    protected HashSet< String > mandatoryIfSubstitutionElseForbidden;
+    protected HashSet< String > mandatoryInLLN0ElseOptional;
+    protected HashSet< String > mandatoryInLLN0ElseForbidden;
+    protected HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional;
+    protected HashSet< String > mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional;
+    protected HashSet< String > mandatoryIfAnalogValueIncludesIElseForbidden;
+    protected HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden;
+    protected HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden;
+    protected HashSet< String > mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional;
+    protected HashSet< String > mandatoryInRootLogicalDeviceElseOptional;
+    protected HashSet< String > mandatoryIfControlSupportsTimeElseOptional;
+    protected HashMap< String, String > oneOrMoreIfSiblingPresentElseForbidden;
+    protected HashSet< String > mandatoryIfControlSupportsSecurity1ElseOptional;
+    protected HashSet< String > mandatoryIfControlSupportsSecurity2ElseOptional;
+    protected HashMap< String, String > optionalIfSiblingPresentElseForbidden;
+    protected HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2;
+    protected HashSet< String > mandatoryIfMeasuredValueExposesRange;
+    protected HashSet< String > optionalIfPhsRefIsSynchrophasorElseMandatory;
+    
+    protected final IRiseClipseConsole console = AbstractRiseClipseConsole.getConsole();
+    
+    public GenericPresenceConditionValidator( NsdModel nsdModel ) {
+        createSpecifications( nsdModel );
+        checkSpecification();
+    }
+    
+    protected abstract void createSpecifications( NsdModel nsdModel );
+
+    protected abstract String getPresenceConditionValidatorName();
+
+    protected abstract String getNsdModelName();
+    protected abstract String getNsdModelClassName();
+    protected abstract String getNsdComponentClassName();
+
+    protected abstract String getSclModelClassName();
+    protected abstract String getSclComponentClassName();
+
+    public void reset() {
+        for( String sclComponent : presentSclComponent.keySet() ) {
+            presentSclComponent.put( sclComponent, null );
+        }
+    }
+    
+    protected void addSpecification( String name, String presCond, String presCondArgs, Doc doc ) {
+        if( presentSclComponent.containsKey( name )) {
+            console.warning( "[NSD setup] " + name + " has already been added to " + getPresenceConditionValidatorName() );
+            return;
+        }
+        presentSclComponent.put( name, null );
+
+        switch( presCond ) {
+        case "M" :
+            // Element is mandatory
+            if( mandatory == null ) mandatory = new HashSet<>();
+            mandatory.add( name );
+            break;
+        case "O" :
+            // Element is optional
+            if( optional == null ) optional = new HashSet<>();
+            optional.add( name );
+            break;
+        case "F" :
+            // Element is forbidden
+            if( forbidden == null ) forbidden = new HashSet<>();
+            forbidden.add( name );
+            break;
+        case "na" :
+            // Element is not applicable
+            // -> TODO: what does it mean ? what do we have to check ?
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"na\" in PresenceCondition" );
+            if( notApplicable == null ) notApplicable = new HashSet<>();
+            notApplicable.add( name );
+            break;
+        case "Mmulti" :
+            // At least one element shall be present; all instances have an instance number > 0
+            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"Mmulti\" in PresenceCondition" );
+            if( mandatoryMulti == null ) mandatoryMulti = new HashSet<>();
+            mandatoryMulti.add( name );
+            break;
+        case "Omulti" :
+            // Zero or more elements may be present; all instances have an instance number > 0
+            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"Omulti\" in PresenceCondition" );
+            if( optionalMulti == null ) optionalMulti = new HashSet<>();
+            optionalMulti.add( name );
+            break;
+        case "AtLeastOne" :
+            // Parameter n: group number (> 0).
+            // At least one of marked elements of a group n shall be present
+            if( atLeastOne == null ) atLeastOne = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not a positive integer" );
+                    break;
+                }
+                if( ! atLeastOne.containsKey( arg )) {
+                    atLeastOne.put( arg, new HashSet<>() );
+                }
+                atLeastOne.get( arg ).add( name );
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not an integer" );
+                break;
+            }
+        case "AtMostOne" :
+            // At most one of marked elements shall be present
+            if( atMostOne == null ) atMostOne = new HashSet<>();
+            atMostOne.add( name );
+            break;
+        case "AllOrNonePerGroup" :
+            // Parameter n: group number (> 0).
+            // All or none of the elements of a group n shall be present
+            if( allOrNonePerGroup == null ) allOrNonePerGroup = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not a positive integer" );
+                    break;
+                }
+                if( ! allOrNonePerGroup.containsKey( arg )) {
+                    allOrNonePerGroup.put( arg, new HashSet<>() );
+                }
+                allOrNonePerGroup.get( arg ).add( name );
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not an integer" );
+                break;
+            }
+        case "AllOnlyOneGroup" :
+            // Parameter n: group number (> 0).
+            // All elements of only one group n shall be present
+            if( allOnlyOneGroup == null ) allOnlyOneGroup = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not a positive integer" );
+                    break;
+                }
+                if( ! allOnlyOneGroup.containsKey( arg )) {
+                    allOnlyOneGroup.put( arg, new HashSet<>() );
+                }
+                allOnlyOneGroup.get( arg ).add( name );
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not an integer" );
+                break;
+            }
+        case "AllAtLeastOneGroup" :
+            // Parameter n: group number (> 0).
+            // All elements of at least one group n shall be present
+            if( allAtLeastOneGroup == null ) allAtLeastOneGroup = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not a positive integer" );
+                    break;
+                }
+                if( ! allAtLeastOneGroup.containsKey( arg )) {
+                    allAtLeastOneGroup.put( arg, new HashSet<>() );
+                }
+                allAtLeastOneGroup.get( arg ).add( name );
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not an integer" );
+                break;
+            }
+        case "MF" :
+            // Parameter sibling: sibling element name.
+            // Mandatory if sibling element is present, otherwise forbidden
+            if( mandatoryIfSiblingPresentElseForbidden == null ) mandatoryIfSiblingPresentElseForbidden = new HashMap<>();
+            mandatoryIfSiblingPresentElseForbidden.put( name, presCondArgs );
+            break;
+        case "MO" :
+            // Parameter sibling: sibling element name.
+            // Mandatory if sibling element is present, otherwise optional
+            if( mandatoryIfSiblingPresentElseOptional == null ) mandatoryIfSiblingPresentElseOptional = new HashMap<>();
+            mandatoryIfSiblingPresentElseOptional.put( name, presCondArgs );
+            break;
+        case "OM" :
+            // Parameter sibling: sibling element name.
+            // Optional if sibling element is present, otherwise mandatory
+            if( optionalIfSiblingPresentElseMandatory == null ) optionalIfSiblingPresentElseMandatory = new HashMap<>();
+            optionalIfSiblingPresentElseMandatory.put( name, presCondArgs );
+            break;
+        case "FM" :
+            // Parameter sibling: sibling element name.
+            // Forbidden if sibling element is present, otherwise mandatory
+            if( forbiddenIfSiblingPresentElseMandatory == null ) forbiddenIfSiblingPresentElseMandatory = new HashMap<>();
+            forbiddenIfSiblingPresentElseMandatory.put( name, presCondArgs );
+            break;
+        case "MOcond" :
+            // Parameter condID: condition number (> 0).
+            // Textual presence condition (non-machine processable) with reference condID to context specific text.
+            // If satisfied, the element is mandatory, otherwise optional
+            if( mandatoryIfTextConditionElseOptional == null ) mandatoryIfTextConditionElseOptional = new HashMap<>();
+            if( mandatoryIfTextConditionElseOptionalDoc == null ) mandatoryIfTextConditionElseOptionalDoc = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not a positive integer" );
+                    break;
+                }
+                mandatoryIfTextConditionElseOptional.put( name, presCondArgs );
+                mandatoryIfTextConditionElseOptionalDoc.put( name, doc.getMixed().get( 0 ).getValue().toString() );
+                
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not an integer" );
+                break;
+            }
+        case "MFcond" :
+            // Parameter condID: condition number (> 0).
+            // Textual presence condition (non-machine processable) with reference condID to context specific text.
+            // If satisfied, the element is mandatory, otherwise forbidden
+            if( mandatoryIfTextConditionElseForbidden == null ) mandatoryIfTextConditionElseForbidden = new HashMap<>();
+            if( mandatoryIfTextConditionElseForbiddenDoc == null ) mandatoryIfTextConditionElseForbiddenDoc = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
+                    break;
+                }
+                mandatoryIfTextConditionElseForbidden.put( name, presCondArgs );
+                mandatoryIfTextConditionElseForbiddenDoc.put( name, doc.getMixed().get( 0 ).getValue().toString() );
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
+                break;
+            }
+        case "OFcond" :
+            // Parameter condID: condition number (> 0).
+            // Textual presence condition (non-machine processable) with reference condID to context specific text.
+            // If satisfied, the element is optional, otherwise forbidden
+            if( optionalIfTextConditionElseForbidden == null ) optionalIfTextConditionElseForbidden = new HashMap<>();
+            if( optionalIfTextConditionElseForbiddenDoc == null ) optionalIfTextConditionElseForbiddenDoc = new HashMap<>();
+            try {
+                Integer arg = Integer.valueOf( presCondArgs );
+                if( arg <= 0 ) {
+                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
+                    break;
+                }
+                optionalIfTextConditionElseForbidden.put( name, presCondArgs );
+                optionalIfTextConditionElseForbiddenDoc.put( name, doc.getMixed().get( 0 ).getValue().toString() );
+                break;
+            }
+            catch( NumberFormatException e ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
+                break;
+            }
+        case "MmultiRange" :
+            // Parameters min, max: limits for instance number (> 0).
+            // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
+            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MmultiRange\" in PresenceCondition" );
+            if( mandatoryMultiRange == null ) mandatoryMultiRange = new HashMap<>();
+            String[] limits1 = presCondArgs.split( "[ ,]+" );
+            if( limits1.length != 2 ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"MmultiRange\" is not two integers" );
+                break;
+            }
+            Integer min1 = Integer.valueOf( limits1[0] );
+            if( min1 <= 0 ) {
+                console.warning( "[NSD setup] first argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
+                break;
+            }
+            Integer max1 = Integer.valueOf( limits1[1] );
+            if( max1 <= 0 ) {
+                console.warning( "[NSD setup] second argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
+                break;
+            }
+            mandatoryMultiRange.put( name, Pair.of( min1, max1 ));
+            break;
+        case "OmultiRange" :
+            // Parameters min, max: limits for instance number (> 0).
+            // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
+            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"OmultiRange\" in PresenceCondition" );
+            if( optionalMultiRange == null ) optionalMultiRange = new HashMap<>();
+            String[] limits2 = presCondArgs.split( "[ ,]+" );
+            if( limits2.length != 2 ) {
+                console.warning( "[NSD setup] argument of PresenceCondition \"OmultiRange\" is not two integers" );
+                break;
+            }
+            Integer min2 = Integer.valueOf( limits2[0] );
+            if( min2 <= 0 ) {
+                console.warning( "[NSD setup] first argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
+                break;
+            }
+            Integer max2 = Integer.valueOf( limits2[1] );
+            if( max2 <= 0 ) {
+                console.warning( "[NSD setup] second argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
+                break;
+            }
+            optionalMultiRange.put( name, Pair.of( min2, max2 ));
+            break;
+        case "MFsubst" :
+            // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
+            // TODO: how do we know if substitution is supported ?
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MFsubst\" in PresenceCondition" );
+            if( mandatoryIfSubstitutionElseForbidden == null ) mandatoryIfSubstitutionElseForbidden = new HashSet<>();
+            mandatoryIfSubstitutionElseForbidden.add( name );
+            break;
+        case "MOln0" :
+            // Element is mandatory in the context of LLN0; otherwise optional
+            if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>();
+            mandatoryInLLN0ElseOptional.add( name );
+            break;
+        case "MFln0" :
+            // Element is mandatory in the context of LLN0; otherwise forbidden
+            if( mandatoryInLLN0ElseForbidden == null ) mandatoryInLLN0ElseForbidden = new HashSet<>();
+            mandatoryInLLN0ElseForbidden.add( name );
+            break;
+        case "MOlnNs" :
+            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
+            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOlnNs\" in PresenceCondition" );
+            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional = new HashSet<>();
+            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional.add( name );
+            break;
+        case "MOdataNs" :
+            // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
+            // otherwise optional. See IEC 61850-7-1 for use of name space
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOdataNs\" in PresenceCondition" );
+            if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional == null ) mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional = new HashSet<>();
+            mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional.add( name );
+            break;
+        case "MFscaledAV" :
+            // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
+            // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
+            // the description of scaling remains mandatory for their (SCL) configuration
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MFscaledAV\" in PresenceCondition" );
+            if( mandatoryIfAnalogValueIncludesIElseForbidden == null ) mandatoryIfAnalogValueIncludesIElseForbidden = new HashSet<>();
+            mandatoryIfAnalogValueIncludesIElseForbidden.add( name );
+            break;
+        case "MFscaledMagV" :
+            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
+            // *See MFscaledAV
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MFscaledMagV\" in PresenceCondition" );
+            if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden = new HashSet<>();
+            mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden.add( name );
+            break;
+        case "MFscaledAngV" :
+            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
+            // *See MFscaledAV
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MFscaledAngV\" in PresenceCondition" );
+            if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden = new HashSet<>();
+            mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden.add( name );
+            break;
+        case "MOrms" :
+            // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
+            // (value of data attribute 'hvRef' is 'rms'), optional otherwise
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOrms\" in PresenceCondition" );
+            if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional == null ) mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional = new HashSet<>();
+            mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional.add( name );
+            break;
+        case "MOrootLD" :
+            // Element is mandatory in the context of a root logical device; otherwise it is optional
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOrootLD\" in PresenceCondition" );
+            if( mandatoryInRootLogicalDeviceElseOptional == null ) mandatoryInRootLogicalDeviceElseOptional = new HashSet<>();
+            mandatoryInRootLogicalDeviceElseOptional.add( name );
+            break;
+        case "MOoperTm" :
+            // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOoperTm\" in PresenceCondition" );
+            if( mandatoryIfControlSupportsTimeElseOptional == null ) mandatoryIfControlSupportsTimeElseOptional = new HashSet<>();
+            mandatoryIfControlSupportsTimeElseOptional.add( name );
+            break;
+        case "MmultiF" :
+            // Parameter sibling: sibling element name.
+            // One or more elements must be present if sibling element is present, otherwise forbidden
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MmultiF\" in PresenceCondition" );
+            if( oneOrMoreIfSiblingPresentElseForbidden == null ) oneOrMoreIfSiblingPresentElseForbidden = new HashMap<>();
+            oneOrMoreIfSiblingPresentElseForbidden.put( name, presCondArgs );
+            break;
+        case "MOsbo" :
+            // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
+            // otherwise optional and value is of no impact
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOsbo\" in PresenceCondition" );
+            if( mandatoryIfControlSupportsSecurity1ElseOptional == null ) mandatoryIfControlSupportsSecurity1ElseOptional = new HashSet<>();
+            mandatoryIfControlSupportsSecurity1ElseOptional.add( name );
+            break;
+        case "MOenhanced" :
+            // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
+            // otherwise optional and value is of no impact
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MOenhanced\" in PresenceCondition" );
+            if( mandatoryIfControlSupportsSecurity2ElseOptional == null ) mandatoryIfControlSupportsSecurity2ElseOptional = new HashSet<>();
+            mandatoryIfControlSupportsSecurity2ElseOptional.add( name );
+            break;
+        case "MONamPlt" :
+            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
+            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
+            // TODO: same as "MOlnNs" ?
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MONamPlt\" in PresenceCondition" );
+            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 = new HashSet<>();
+            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2.add( name );
+            break;
+        case "OF" :
+            // Parameter sibling: sibling element name.
+            // Optional if sibling element is present, otherwise forbidden
+            if( optionalIfSiblingPresentElseForbidden == null ) optionalIfSiblingPresentElseForbidden = new HashMap<>();
+            optionalIfSiblingPresentElseForbidden.put( name, presCondArgs );
+            break;
+        case "MORange" :
+            // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
+            // (with the attribute range respectively rangeAng)
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"MORange\" in PresenceCondition" );
+            if( mandatoryIfMeasuredValueExposesRange == null ) mandatoryIfMeasuredValueExposesRange = new HashSet<>();
+            mandatoryIfMeasuredValueExposesRange.add( name );
+            break;
+        case "OMSynPh" :
+            // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
+            console.warning( "[NSD setup] NOT IMPLEMENTED: " + getNsdComponentClassName() + " " + name + " declared as \"OMSynPh\" in PresenceCondition" );
+            if( optionalIfPhsRefIsSynchrophasorElseMandatory == null ) optionalIfPhsRefIsSynchrophasorElseMandatory = new HashSet<>();
+            optionalIfPhsRefIsSynchrophasorElseMandatory.add( name );
+            break;
+        default:
+            console.warning( "[NSD setup] the PresenceCondition " + presCond + " of AnyLNClass " + name + " is unknown" );
+            break;
+        }
+        
+    }
+    
+    protected void checkSpecification() {
+        // TODO: do we have to check the presence of the sibling in inherited AbstractLNClass ?
+        if( mandatoryIfSiblingPresentElseForbidden != null ) {
+            for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
+                if( ! presentSclComponent.containsKey( e.getValue() )) {
+                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" );
+                }
+            }
+        }
+        if( mandatoryIfSiblingPresentElseOptional != null ) {
+            for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
+                if( ! presentSclComponent.containsKey( e.getValue() )) {
+                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" );
+                }
+            }
+        }
+        if( optionalIfSiblingPresentElseMandatory != null ) {
+            for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) {
+                if( ! presentSclComponent.containsKey( e.getValue() )) {
+                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" );
+                }
+            }
+        }
+        if( forbiddenIfSiblingPresentElseMandatory != null ) {
+            for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
+                if( ! presentSclComponent.containsKey( e.getValue() )) {
+                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" );
+                }
+            }
+        }
+        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
+            for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) {
+                if( ! presentSclComponent.containsKey( e.getValue() )) {
+                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" );
+                }
+            }
+        }
+        if( optionalIfSiblingPresentElseForbidden != null ) {
+            for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) {
+                if( ! presentSclComponent.containsKey( e.getValue() )) {
+                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" );
+                }
+            }
+        }
+    }
+
+    public boolean addModelData( @NonNull SclComponent sclComponent, String sclComponentName, DiagnosticChain diagnostics ) {
+        if( ! presentSclComponent.containsKey( sclComponentName )) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] " + getSclComponentClassName() + " " + sclComponentName + " (line " + sclComponent.getLineNumber() + ") not found in " + getNsdModelClassName() + " " + getNsdModelName(),
+                    new Object[] { sclComponent } ));
+            return false;
+        }
+
+        if( presentSclComponent.get( sclComponentName ) != null ) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] " + getSclComponentClassName() + " " + sclComponentName + " (line " + sclComponent.getLineNumber() + ") already present in " + getNsdModelClassName() + " " + getNsdModelName(),
+                    new Object[] { sclComponent } ));
+            return false;
+        }
+        presentSclComponent.put( sclComponentName, sclComponent );
+        return true;
+    }
+    
+    public boolean validate( SclModel sclModel, DiagnosticChain diagnostics ) {
+        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] OldDataAttributePresenceConditionValidator.validate() at line " + sclModel.getLineNumber() );
+
+        boolean res = true;
+        
+        // presCond: "M"
+        // Element is mandatory
+        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
+        if( mandatory != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"M\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( String name : this.mandatory ) {
+                if( presentSclComponent.get( name ) == null ) {
+                  diagnostics.add( new BasicDiagnostic(
+                          Diagnostic.ERROR,
+                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                          0,
+                          "[NSD validation] " + getSclComponentClassName() + " " + name + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                          new Object[] { sclModel } ));
+                  res = false;
+                }
+            }
+        }
+
+        // presCond: "O"
+        // Element is optional
+        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
+        if( optional != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"O\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( String name : this.optional ) {
+                if( presentSclComponent.get( name ) == null ) {
+                    // Nothing
+                }
+            }
+        }
+
+        // presCond: "F"
+        // Element is forbidden
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( forbidden != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"F\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( String name : this.forbidden ) {
+                if( presentSclComponent.get( name ) != null ) {
+                  diagnostics.add( new BasicDiagnostic(
+                          Diagnostic.ERROR,
+                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                          0,
+                          "[NSD validation] " + getSclComponentClassName() + " " + name + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                          new Object[] { sclModel } ));
+                  res = false;
+                }
+            }
+        }
+
+        // presCond: "na"
+        // Element is not applicable
+        // Usage in standard NSD files (version 2007B): only for dsPresCond
+        // -> TODO: what does it mean ? what do we have to check ?
+        if( notApplicable != null ) {
+            for( String name : notApplicable ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"na\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+        
+        // presCond: "Mmulti"
+        // At least one element shall be present; all instances have an instance number > 0
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( mandatoryMulti != null ) {
+            for( String name : mandatoryMulti ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"Mmulti\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "Omulti"
+        // Zero or more elements may be present; all instances have an instance number > 0
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( optionalMulti != null ) {
+            for( String name : optionalMulti ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"Omulti\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+        
+        // presCond: "AtLeastOne"
+        // Parameter n: group number (> 0).
+        // At least one of marked elements of a group n shall be present
+        // Usage in standard NSD files (version 2007B): DataObject and SubDataObject and DataAttribute and SubDataAttribute
+        if( atLeastOne != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtLeastOne\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) {
+                boolean groupOK = false;
+                for( String member : e1.getValue() ) {
+                    if( presentSclComponent.get( member ) != null ) {
+                        groupOK = true;
+                        break;
+                    }
+                }
+                if( ! groupOK ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.ERROR,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] group " + e1.getKey() + " has no elements in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                    res = false;
+                }
+            }
+        }
+        
+        // presCond: "AtMostOne" :
+        // At most one of marked elements shall be present
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( atMostOne != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtMostOne\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            int count = 0;
+            for( String s : atMostOne ) {
+                if( presentSclComponent.get( s ) != null ) {
+                    ++count;
+                }
+            }
+            if( count > 1 ) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] LNodeType (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has more than one element marked AtMostOne",
+                        new Object[] { sclModel } ));
+                res = false;
+            }
+        }
+        
+        // presCond: "AllOrNonePerGroup" :
+        // Parameter n: group number (> 0).
+        // All or none of the elements of a group n shall be present
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        if( allOrNonePerGroup != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOrNonePerGroup\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) {
+                int groupCount = 0;
+                for( String member : e1.getValue() ) {
+                    if( presentSclComponent.get( member ) != null ) {
+                        ++groupCount;
+                    }
+                }
+                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.ERROR,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                    res = false;
+                }
+            }
+        }
+        
+        // presCond: "AllOnlyOneGroup" :
+        // Parameter n: group number (> 0).
+        // All elements of only one group n shall be present
+        // Usage in standard NSD files (version 2007B): DataObject and SubDataAttribute
+        if( allOnlyOneGroup != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOnlyOneGroup\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            int groupNumber = 0;
+            for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) {
+                int groupCount = 0;
+                for( String member : e1.getValue() ) {
+                    if( presentSclComponent.get( member ) != null ) {
+                        ++groupCount;
+                    }
+                }
+                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.ERROR,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                    res = false;
+                }
+                else if( groupCount > 0 ) {
+                    if( groupNumber == 0 ) {
+                        groupNumber = e1.getKey();
+                    }
+                    else {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] LNodeType (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has several groups with all elements",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+            }
+            if( groupNumber == 0 ) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] no group in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has all elements",
+                        new Object[] { sclModel } ));
+                res = false;
+            }
+        }
+        
+        // presCond: "AllAtLeastOneGroup" :
+        // Parameter n: group number (> 0).
+        // All elements of at least one group n shall be present
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        if( allAtLeastOneGroup != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllAtLeastOneGroup\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            int groupNumber = 0;
+            for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) {
+                int groupCount = 0;
+                for( String member : e1.getValue() ) {
+                    if( presentSclComponent.get( member ) != null ) {
+                        ++groupCount;
+                    }
+                }
+                if( groupCount == e1.getValue().size() ) {
+                    groupNumber = e1.getKey();
+                }
+            }
+            if( groupNumber == 0 ) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] no group in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has all elements",
+                        new Object[] { sclModel } ));
+                res = false;
+            }
+        }
+        
+        // presCond: "MF" :
+        // Parameter sibling: sibling element name.
+        // Mandatory if sibling element is present, otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( mandatoryIfSiblingPresentElseForbidden != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MF\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
+                if( presentSclComponent.get( entry.getValue() ) != null ) {
+                    if( presentSclComponent.get( entry.getKey() ) == null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+                else {
+                    if( presentSclComponent.get( entry.getKey() ) != null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is not present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+            }
+        }
+        
+        // presCond: "MO" :
+        // Parameter sibling: sibling element name.
+        // Mandatory if sibling element is present, otherwise optional
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        if( mandatoryIfSiblingPresentElseOptional != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MO\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
+                if( presentSclComponent.get( entry.getValue() ) != null ) {
+                    if( presentSclComponent.get( entry.getKey() ) == null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+            }
+        }
+        
+        // presCond: "OM" :
+        // Parameter sibling: sibling element name.
+        // Optional if sibling element is present, otherwise mandatory
+        // Usage in standard NSD files (version 2007B): None
+        if( optionalIfSiblingPresentElseMandatory != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OM\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) {
+                if( presentSclComponent.get( entry.getValue() ) == null ) {
+                    if( presentSclComponent.get( entry.getKey() ) == null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is not present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+            }
+        }
+        
+        // presCond: "FM" :
+        // Parameter sibling: sibling element name.
+        // Forbidden if sibling element is present, otherwise mandatory
+        // Usage in standard NSD files (version 2007B): None
+        if( forbiddenIfSiblingPresentElseMandatory != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"FM\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
+                if( presentSclComponent.get( entry.getValue() ) != null ) {
+                    if( presentSclComponent.get( entry.getKey() ) != null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+                else {
+                    if( presentSclComponent.get( entry.getKey() ) == null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is not present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+            }
+        }
+        
+        // presCond: "MOcond" :
+        // Parameter condID: condition number (> 0).
+        // Textual presence condition (non-machine processable) with reference condID to context specific text.
+        // If satisfied, the element is mandatory, otherwise optional
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( mandatoryIfTextConditionElseOptional != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOcond\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) {
+                String doc = mandatoryIfTextConditionElseOptionalDoc.get( entry.getKey() );
+
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.WARNING,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with "
+                                + getNsdModelClassName() + " " + getNsdModelName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is "
+                                + ( presentSclComponent.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
+                        new Object[] { sclModel } ));
+            }
+        }
+        
+        // presCond: "MFcond" :
+        // Parameter condID: condition number (> 0).
+        // Textual presence condition (non-machine processable) with reference condID to context specific text.
+        // If satisfied, the element is mandatory, otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( mandatoryIfTextConditionElseForbidden != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFcond\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) {
+                String doc = mandatoryIfTextConditionElseForbiddenDoc.get( entry.getKey() );
+
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.WARNING,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with "
+                                + getNsdModelClassName() + " " + getNsdModelName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
+                                + ( presentSclComponent.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
+                        new Object[] { sclModel } ));
+            }
+        }
+        
+        // presCond: "OFcond" :
+        // Parameter condID: condition number (> 0).
+        // Textual presence condition (non-machine processable) with reference condID to context specific text.
+        // If satisfied, the element is optional, otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( optionalIfTextConditionElseForbidden != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OFcond\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) {
+                String doc = optionalIfTextConditionElseForbiddenDoc.get( entry.getKey() );
+
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.WARNING,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is optional in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with "
+                                + getNsdModelClassName() + " " + getNsdModelName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
+                                + ( presentSclComponent.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
+                        new Object[] { sclModel } ));
+            }
+        }
+        
+        // presCond: "MmultiRange" :
+        // Parameters min, max: limits for instance number (> 0).
+        // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
+        // Usage in standard NSD files (version 2007B): None
+        if( mandatoryMultiRange != null ) {
+            for( String name : mandatoryMultiRange.keySet() ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MmultiRange\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "OmultiRange" :
+        // Parameters min, max: limits for instance number (> 0).
+        // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( optionalMultiRange != null ) {
+            for( String name : optionalMultiRange.keySet() ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"OmultiRange\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MFsubst" :
+        // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfSubstitutionElseForbidden != null ) {
+            for( String name : mandatoryIfSubstitutionElseForbidden ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MFsubst\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+        
+        // presCond: "MOln0" :
+        // Element is mandatory in the context of LLN0; otherwise optional
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        if( mandatoryInLLN0ElseOptional != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOln0\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            res = validateMOln0( sclModel, diagnostics ) && res;
+        }
+        
+        // presCond: "MFln0" :
+        // Element is mandatory in the context of LLN0; otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        if( mandatoryInLLN0ElseForbidden != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFln0\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            res = validateMFln0( sclModel, diagnostics ) && res;
+        }
+
+        // presCond: "MOlnNs" :
+        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
+        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO: The meaning is not clear.
+        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional != null ) {
+            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOlnNs\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MOdataNs" :
+        // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
+        // otherwise optional. See IEC 61850-7-1 for use of name space
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO: The meaning is not clear.
+        if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional != null ) {
+            for( String name : mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOdataNs\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MFscaledAV" :
+        // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
+        // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
+        // the description of scaling remains mandatory for their (SCL) configuration
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfAnalogValueIncludesIElseForbidden != null ) {
+            for( String name : mandatoryIfAnalogValueIncludesIElseForbidden ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MFscaledMagV" :
+        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
+        // *See MFscaledAV
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden != null ) {
+            for( String name : mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MFscaledAngV" :
+        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
+        // *See MFscaledAV
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden != null ) {
+            for( String name : mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MOrms" :
+        // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
+        // (value of data attribute 'hvRef' is 'rms'), optional otherwise
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional != null ) {
+            for( String name : mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOrms\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MOrootLD" :
+        // Element is mandatory in the context of a root logical device; otherwise it is optional
+        // Usage in standard NSD files (version 2007B): DataObject
+        if( mandatoryInRootLogicalDeviceElseOptional != null ) {
+            for( String name : mandatoryInRootLogicalDeviceElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOrootLD\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MOoperTm" :
+        // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfControlSupportsTimeElseOptional != null ) {
+            for( String name : mandatoryIfControlSupportsTimeElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOoperTm\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MmultiF" :
+        // Parameter sibling: sibling element name.
+        // One or more elements must be present if sibling element is present, otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataObject
+        // TODO: One or more elements ? Is there an instance number ?
+        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
+            for( String name : oneOrMoreIfSiblingPresentElseForbidden.keySet() ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MmultiF\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MOsbo" :
+        // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
+        // otherwise optional and value is of no impact
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfControlSupportsSecurity1ElseOptional != null ) {
+            for( String name : mandatoryIfControlSupportsSecurity1ElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOsbo\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MOenhanced" :
+        // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
+        // otherwise optional and value is of no impact
+        // Usage in standard NSD files (version 2007B): DataAttribute
+        // TODO
+        if( mandatoryIfControlSupportsSecurity2ElseOptional != null ) {
+            for( String name : mandatoryIfControlSupportsSecurity2ElseOptional ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MOenhanced\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "MONamPlt" :
+        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
+        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
+        // Usage in standard NSD files (version 2007B): DataObject
+        // TODO: same as "MOlnNs" ?
+        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 != null ) {
+            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MONamPlt\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "OF" :
+        // Parameter sibling: sibling element name.
+        // Optional if sibling element is present, otherwise forbidden
+        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute
+        if( optionalIfSiblingPresentElseForbidden != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OF\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) {
+                if( presentSclComponent.get( entry.getValue() ) == null ) {
+                    if( presentSclComponent.get( entry.getKey() ) != null ) {
+                        diagnostics.add( new BasicDiagnostic(
+                                Diagnostic.ERROR,
+                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                                0,
+                                "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass "
+                                        + getNsdModelName() + " because sibling " + entry.getValue() + " is not present",
+                                new Object[] { sclModel } ));
+                        res = false;
+                    }
+                }
+            }
+        }
+
+        // presCond: "MORange" :
+        // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
+        // (with the attribute range respectively rangeAng)
+        // Usage in standard NSD files (version 2007B): SubDataAttribute
+        // TODO
+        if( mandatoryIfMeasuredValueExposesRange != null ) {
+            for( String name : mandatoryIfMeasuredValueExposesRange ) {
+                if( presentSclComponent.get( name ) != null ) {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.WARNING,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] verification of PresenceCondition \"MORange\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                            new Object[] { sclModel } ));
+                }
+            }
+        }
+
+        // presCond: "OMSynPh" :
+        // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
+        // Usage in standard NSD files (version 2007B): SubDataObject
+        // TODO
+        if( optionalIfPhsRefIsSynchrophasorElseMandatory != null ) {
+            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OMSynPh\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() );
+            res = validateOMSynPh( sclModel, diagnostics ) && res;
+        }
+
+        return res;
+    }
+
+    protected abstract boolean validateMFln0( SclModel sclModel, DiagnosticChain diagnostics );
+
+    protected abstract boolean validateMOln0( SclModel sclModel, DiagnosticChain diagnostics );
+
+    protected abstract boolean validateOMSynPh( SclModel sclModel, DiagnosticChain diagnostics );
+
+}
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java
index a6e2fd4..228059f 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java
@@ -45,9 +45,10 @@ public class LNClassValidator {
         .forEach( lnClass -> validators.put( lnClass.getName(), new LNClassValidator( lnClass )));
     }
 
+    private static HashSet< String > validatedLNodeType = new HashSet<>();
+
     private DataObjectPresenceConditionValidator dataObjectPresenceConditionValidator;
     private HashMap< String, CDCValidator > dataObjectValidatorMap = new HashMap<>();
-    private HashSet< LNodeType > validatedLNodeType = new HashSet<>();
 
     private LNClassValidator( AnyLNClass anyLNClass ) {
         dataObjectPresenceConditionValidator = DataObjectPresenceConditionValidator.get( anyLNClass );
@@ -69,9 +70,9 @@ public class LNClassValidator {
     }
     
     public boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) {
-        if( validatedLNodeType.contains( lNodeType )) return true;
+        if( validatedLNodeType.contains( lNodeType.getId() )) return true;
         AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] LNClassValidator.validateLNodeType( " + lNodeType.getId() + " ) at line " + lNodeType.getLineNumber() );
-        validatedLNodeType.add( lNodeType );
+        validatedLNodeType.add( lNodeType.getId() );
 
         boolean res = true;
 
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java
index 37f5d83..67af54a 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java
@@ -19,21 +19,17 @@
 package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd;
 
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map.Entry;
-
-import org.apache.commons.lang3.tuple.Pair;
 import org.eclipse.emf.common.util.BasicDiagnostic;
 import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.jdt.annotation.Nullable;
+
 import fr.centralesupelec.edf.riseclipse.iec61850.nsd.ConstructedAttribute;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.BDA;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.DAType;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
-import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
-import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole;
 
-public class SubDataAttributePresenceConditionValidator {
+public class SubDataAttributePresenceConditionValidator extends GenericPresenceConditionValidator< ConstructedAttribute, DAType, @Nullable BDA >{
     
     private static HashMap< String, SubDataAttributePresenceConditionValidator > validators = new HashMap<>();
     
@@ -46,1332 +42,93 @@ public class SubDataAttributePresenceConditionValidator {
     
     private ConstructedAttribute constructedAttribute;
     
-    // Name of the SubDataAttribute/BDA, BDA
-    private HashMap< String, BDA > presentBDA = new HashMap<>();
-    
-    private HashSet< String > mandatory;
-    private HashSet< String > optional;
-    private HashSet< String > forbidden;
-    private HashSet< String > notApplicable;
-    private HashSet< String > mandatoryMulti;
-    private HashSet< String > optionalMulti;
-    private HashMap< Integer, HashSet< String > > atLeastOne;
-    private HashSet< String > atMostOne;
-    private HashMap< Integer, HashSet< String > > allOrNonePerGroup;
-    private HashMap< Integer, HashSet< String > > allOnlyOneGroup;
-    private HashMap< Integer, HashSet< String > > allAtLeastOneGroup;
-    private HashMap< String, String > mandatoryIfSiblingPresentElseForbidden;
-    private HashMap< String, String > mandatoryIfSiblingPresentElseOptional;
-    private HashMap< String, String > optionalIfSiblingPresentElseMandatory;
-    private HashMap< String, String > forbiddenIfSiblingPresentElseMandatory;
-    private HashMap< String, String > mandatoryIfTextConditionElseOptional;
-    private HashMap< String, String > mandatoryIfTextConditionElseForbidden;
-    private HashMap< String, String > optionalIfTextConditionElseForbidden;
-    private HashMap< String, Pair< Integer, Integer > > mandatoryMultiRange;
-    private HashMap< String, Pair< Integer, Integer > > optionalMultiRange;
-    private HashSet< String > mandatoryIfSubstitutionElseForbidden;
-    private HashSet< String > mandatoryInLLN0ElseOptional;
-    private HashSet< String > mandatoryInLLN0ElseForbidden;
-    private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional;
-    private HashSet< String > mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional;
-    private HashSet< String > mandatoryIfAnalogValueIncludesIElseForbidden;
-    private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden;
-    private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden;
-    private HashSet< String > mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional;
-    private HashSet< String > mandatoryInRootLogicalDeviceElseOptional;
-    private HashSet< String > mandatoryIfControlSupportsTimeElseOptional;
-    private HashMap< String, String > oneOrMoreIfSiblingPresentElseForbidden;
-    private HashSet< String > mandatoryIfControlSupportsSecurity1ElseOptional;
-    private HashSet< String > mandatoryIfControlSupportsSecurity2ElseOptional;
-    private HashMap< String, String > optionalIfSiblingPresentElseForbidden;
-    private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2;
-    private HashSet< String > mandatoryIfMeasuredValueExposesRange;
-    private HashSet< String > optionalIfPhsRefIsSynchrophasorElseMandatory;
-    
-    private final IRiseClipseConsole console = AbstractRiseClipseConsole.getConsole();
-    
     public SubDataAttributePresenceConditionValidator( ConstructedAttribute constructedAttribute ) {
+        super( constructedAttribute );
+
         this.constructedAttribute = constructedAttribute;
-        
+    }
+    
+    @Override
+    protected void createSpecifications( ConstructedAttribute constructedAttribute ) {
         constructedAttribute
         .getSubDataAttribute()
         .stream()
-        .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs() ) );
-
-        checkSpecification();
+        .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs(), sda.getRefersToPresCondArgsDoc() ) );
     }
     
-    public void reset() {
-        for( String bda : presentBDA.keySet() ) {
-            presentBDA.put( bda, null );
-        }
+    @Override
+    protected String getPresenceConditionValidatorName() {
+        return "SubDataAttributePresenceConditionValidator";
     }
-    
-    private void addSpecification( String name, String presCond, String presCondArgs ) {
-        if( presentBDA.containsKey( name )) {
-            console.warning( "[NSD setup] " + name + " has already been added to SubDataAttributePresenceConditionValidator" );
-            return;
-        }
-        presentBDA.put( name, null );
 
-        switch( presCond ) {
-        case "M" :
-            // Element is mandatory
-            if( mandatory == null ) mandatory = new HashSet<>();
-            mandatory.add( name );
-            break;
-        case "O" :
-            // Element is optional
-            if( optional == null ) optional = new HashSet<>();
-            optional.add( name );
-            break;
-        case "F" :
-            // Element is forbidden
-            if( forbidden == null ) forbidden = new HashSet<>();
-            forbidden.add( name );
-            break;
-        case "na" :
-            // Element is not applicable
-            // -> TODO: what does it mean ? what do we have to check ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"na\" in PresenceCondition" );
-            if( notApplicable == null ) notApplicable = new HashSet<>();
-            notApplicable.add( name );
-            break;
-        case "Mmulti" :
-            // At least one element shall be present; all instances have an instance number > 0
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"Mmulti\" in PresenceCondition" );
-            if( mandatoryMulti == null ) mandatoryMulti = new HashSet<>();
-            mandatoryMulti.add( name );
-            break;
-        case "Omulti" :
-            // Zero or more elements may be present; all instances have an instance number > 0
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"Omulti\" in PresenceCondition" );
-            if( optionalMulti == null ) optionalMulti = new HashSet<>();
-            optionalMulti.add( name );
-            break;
-        case "AtLeastOne" :
-            // Parameter n: group number (> 0).
-            // At least one of marked elements of a group n shall be present
-            if( atLeastOne == null ) atLeastOne = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not a positive integer" );
-                    break;
-                }
-                if( ! atLeastOne.containsKey( arg )) {
-                    atLeastOne.put( arg, new HashSet<>() );
-                }
-                atLeastOne.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not an integer" );
-                break;
-            }
-        case "AtMostOne" :
-            // At most one of marked elements shall be present
-            if( atMostOne == null ) atMostOne = new HashSet<>();
-            atMostOne.add( name );
-            break;
-        case "AllOrNonePerGroup" :
-            // Parameter n: group number (> 0).
-            // All or none of the elements of a group n shall be present
-            if( allOrNonePerGroup == null ) allOrNonePerGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allOrNonePerGroup.containsKey( arg )) {
-                    allOrNonePerGroup.put( arg, new HashSet<>() );
-                }
-                allOrNonePerGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not an integer" );
-                break;
-            }
-        case "AllOnlyOneGroup" :
-            // Parameter n: group number (> 0).
-            // All elements of only one group n shall be present
-            if( allOnlyOneGroup == null ) allOnlyOneGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allOnlyOneGroup.containsKey( arg )) {
-                    allOnlyOneGroup.put( arg, new HashSet<>() );
-                }
-                allOnlyOneGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not an integer" );
-                break;
-            }
-        case "AllAtLeastOneGroup" :
-            // Parameter n: group number (> 0).
-            // All elements of at least one group n shall be present
-            if( allAtLeastOneGroup == null ) allAtLeastOneGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allAtLeastOneGroup.containsKey( arg )) {
-                    allAtLeastOneGroup.put( arg, new HashSet<>() );
-                }
-                allAtLeastOneGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not an integer" );
-                break;
-            }
-        case "MF" :
-            // Parameter sibling: sibling element name.
-            // Mandatory if sibling element is present, otherwise forbidden
-            if( mandatoryIfSiblingPresentElseForbidden == null ) mandatoryIfSiblingPresentElseForbidden = new HashMap<>();
-            mandatoryIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MO" :
-            // Parameter sibling: sibling element name.
-            // Mandatory if sibling element is present, otherwise optional
-            if( mandatoryIfSiblingPresentElseOptional == null ) mandatoryIfSiblingPresentElseOptional = new HashMap<>();
-            mandatoryIfSiblingPresentElseOptional.put( name, presCondArgs );
-            break;
-        case "OM" :
-            // Parameter sibling: sibling element name.
-            // Optional if sibling element is present, otherwise mandatory
-            if( optionalIfSiblingPresentElseMandatory == null ) optionalIfSiblingPresentElseMandatory = new HashMap<>();
-            optionalIfSiblingPresentElseMandatory.put( name, presCondArgs );
-            break;
-        case "FM" :
-            // Parameter sibling: sibling element name.
-            // Forbidden if sibling element is present, otherwise mandatory
-            if( forbiddenIfSiblingPresentElseMandatory == null ) forbiddenIfSiblingPresentElseMandatory = new HashMap<>();
-            forbiddenIfSiblingPresentElseMandatory.put( name, presCondArgs );
-            break;
-        case "MOcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is mandatory, otherwise optional
-            if( mandatoryIfTextConditionElseOptional == null ) mandatoryIfTextConditionElseOptional = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not a positive integer" );
-                    break;
-                }
-                mandatoryIfTextConditionElseOptional.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not an integer" );
-                break;
-            }
-        case "MFcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is mandatory, otherwise forbidden
-            if( mandatoryIfTextConditionElseForbidden == null ) mandatoryIfTextConditionElseForbidden = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
-                    break;
-                }
-                mandatoryIfTextConditionElseForbidden.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
-                break;
-            }
-        case "OFcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is optional, otherwise forbidden
-            if( optionalIfTextConditionElseForbidden == null ) optionalIfTextConditionElseForbidden = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
-                    break;
-                }
-                optionalIfTextConditionElseForbidden.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
-                break;
-            }
-        case "MmultiRange" :
-            // Parameters min, max: limits for instance number (> 0).
-            // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MmultiRange\" in PresenceCondition" );
-            if( mandatoryMultiRange == null ) mandatoryMultiRange = new HashMap<>();
-            String[] limits1 = presCondArgs.split( "[ ,]+" );
-            if( limits1.length != 2 ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MmultiRange\" is not two integers" );
-                break;
-            }
-            Integer min1 = Integer.valueOf( limits1[0] );
-            if( min1 <= 0 ) {
-                console.warning( "[NSD setup] first argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
-                break;
-            }
-            Integer max1 = Integer.valueOf( limits1[1] );
-            if( max1 <= 0 ) {
-                console.warning( "[NSD setup] second argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
-                break;
-            }
-            mandatoryMultiRange.put( name, Pair.of( min1, max1 ));
-            break;
-        case "OmultiRange" :
-            // Parameters min, max: limits for instance number (> 0).
-            // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"OmultiRange\" in PresenceCondition" );
-            if( optionalMultiRange == null ) optionalMultiRange = new HashMap<>();
-            String[] limits2 = presCondArgs.split( "[ ,]+" );
-            if( limits2.length != 2 ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"OmultiRange\" is not two integers" );
-                break;
-            }
-            Integer min2 = Integer.valueOf( limits2[0] );
-            if( min2 <= 0 ) {
-                console.warning( "[NSD setup] first argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
-                break;
-            }
-            Integer max2 = Integer.valueOf( limits2[1] );
-            if( max2 <= 0 ) {
-                console.warning( "[NSD setup] second argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
-                break;
-            }
-            optionalMultiRange.put( name, Pair.of( min2, max2 ));
-            break;
-        case "MFsubst" :
-            // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
-            // TODO: how do we know if substitution is supported ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFsubst\" in PresenceCondition" );
-            if( mandatoryIfSubstitutionElseForbidden == null ) mandatoryIfSubstitutionElseForbidden = new HashSet<>();
-            mandatoryIfSubstitutionElseForbidden.add( name );
-            break;
-        case "MOln0" :
-            // Element is mandatory in the context of LLN0; otherwise optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOln0\" in PresenceCondition" );
-            if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>();
-            mandatoryInLLN0ElseOptional.add( name );
-            break;
-        case "MFln0" :
-            // Element is mandatory in the context of LLN0; otherwise forbidden
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFln0\" in PresenceCondition" );
-            if( mandatoryInLLN0ElseForbidden == null ) mandatoryInLLN0ElseForbidden = new HashSet<>();
-            mandatoryInLLN0ElseForbidden.add( name );
-            break;
-        case "MOlnNs" :
-            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOlnNs\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional = new HashSet<>();
-            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional.add( name );
-            break;
-        case "MOdataNs" :
-            // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
-            // otherwise optional. See IEC 61850-7-1 for use of name space
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOdataNs\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional == null ) mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional = new HashSet<>();
-            mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional.add( name );
-            break;
-        case "MFscaledAV" :
-            // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
-            // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
-            // the description of scaling remains mandatory for their (SCL) configuration
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFscaledAV\" in PresenceCondition" );
-            if( mandatoryIfAnalogValueIncludesIElseForbidden == null ) mandatoryIfAnalogValueIncludesIElseForbidden = new HashSet<>();
-            mandatoryIfAnalogValueIncludesIElseForbidden.add( name );
-            break;
-        case "MFscaledMagV" :
-            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
-            // *See MFscaledAV
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFscaledMagV\" in PresenceCondition" );
-            if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden = new HashSet<>();
-            mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden.add( name );
-            break;
-        case "MFscaledAngV" :
-            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
-            // *See MFscaledAV
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFscaledAngV\" in PresenceCondition" );
-            if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden = new HashSet<>();
-            mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden.add( name );
-            break;
-        case "MOrms" :
-            // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
-            // (value of data attribute 'hvRef' is 'rms'), optional otherwise
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOrms\" in PresenceCondition" );
-            if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional == null ) mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional = new HashSet<>();
-            mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional.add( name );
-            break;
-        case "MOrootLD" :
-            // Element is mandatory in the context of a root logical device; otherwise it is optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOrootLD\" in PresenceCondition" );
-            if( mandatoryInRootLogicalDeviceElseOptional == null ) mandatoryInRootLogicalDeviceElseOptional = new HashSet<>();
-            mandatoryInRootLogicalDeviceElseOptional.add( name );
-            break;
-        case "MOoperTm" :
-            // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOoperTm\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsTimeElseOptional == null ) mandatoryIfControlSupportsTimeElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsTimeElseOptional.add( name );
-            break;
-        case "MmultiF" :
-            // Parameter sibling: sibling element name.
-            // One or more elements must be present if sibling element is present, otherwise forbidden
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MmultiF\" in PresenceCondition" );
-            if( oneOrMoreIfSiblingPresentElseForbidden == null ) oneOrMoreIfSiblingPresentElseForbidden = new HashMap<>();
-            oneOrMoreIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MOsbo" :
-            // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
-            // otherwise optional and value is of no impact
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOsbo\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsSecurity1ElseOptional == null ) mandatoryIfControlSupportsSecurity1ElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsSecurity1ElseOptional.add( name );
-            break;
-        case "MOenhanced" :
-            // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
-            // otherwise optional and value is of no impact
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOenhanced\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsSecurity2ElseOptional == null ) mandatoryIfControlSupportsSecurity2ElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsSecurity2ElseOptional.add( name );
-            break;
-        case "MONamPlt" :
-            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-            // TODO: same as "MOlnNs" ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MONamPlt\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 = new HashSet<>();
-            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2.add( name );
-            break;
-        case "OF" :
-            // Parameter sibling: sibling element name.
-            // Optional if sibling element is present, otherwise forbidden
-            if( optionalIfSiblingPresentElseForbidden == null ) optionalIfSiblingPresentElseForbidden = new HashMap<>();
-            optionalIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MORange" :
-            // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
-            // (with the attribute range respectively rangeAng)
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MORange\" in PresenceCondition" );
-            if( mandatoryIfMeasuredValueExposesRange == null ) mandatoryIfMeasuredValueExposesRange = new HashSet<>();
-            mandatoryIfMeasuredValueExposesRange.add( name );
-            break;
-        case "OMSynPh" :
-            // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"OMSynPh\" in PresenceCondition" );
-            if( optionalIfPhsRefIsSynchrophasorElseMandatory == null ) optionalIfPhsRefIsSynchrophasorElseMandatory = new HashSet<>();
-            optionalIfPhsRefIsSynchrophasorElseMandatory.add( name );
-            break;
-        default:
-            console.warning( "[NSD setup] the PresenceCondition " + presCond + " of AnyLNClass " + name + " is unknown" );
-            break;
-        }
-        
+    @Override
+    protected String getNsdModelName() {
+        return constructedAttribute.getName();
     }
-    
-    private void checkSpecification() {
-        // TODO: do we have to check the presence of the sibling in inherited AbstractLNClass ?
-        if( mandatoryIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentBDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( mandatoryIfSiblingPresentElseOptional != null ) {
-            for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
-                if( ! presentBDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( optionalIfSiblingPresentElseMandatory != null ) {
-            for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) {
-                if( ! presentBDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( forbiddenIfSiblingPresentElseMandatory != null ) {
-            for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
-                if( ! presentBDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentBDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( optionalIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentBDA.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-    }
-
-    public boolean addBDA( BDA bda, DiagnosticChain diagnostics ) {
-        if( ! presentBDA.containsKey( bda.getName() )) {
-            diagnostics.add( new BasicDiagnostic(
-                    Diagnostic.ERROR,
-                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                    0,
-                    "[NSD validation] BDA" + bda.getName() + " (line " + bda.getLineNumber() + ") not found in ConstructedAttribute " + constructedAttribute.getName(),
-                    new Object[] { bda } ));
-            return false;
-        }
 
-        if( presentBDA.get( bda.getName() ) != null ) {
-            diagnostics.add( new BasicDiagnostic(
-                    Diagnostic.ERROR,
-                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                    0,
-                    "[NSD validation] BDA" + bda.getName() + " (line " + bda.getLineNumber() + ") already present in ConstructedAttribute " + constructedAttribute.getName(),
-                    new Object[] { bda } ));
-            return false;
-        }
-        presentBDA.put( bda.getName(), bda );
-        return true;
+    @Override
+    protected String getNsdModelClassName() {
+        return "ConstructedAttribute";
     }
-    
-    public boolean validate( DAType daType, DiagnosticChain diagnostics ) {
-        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] DataAttributePresenceConditionValidator.validate(id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-
-        boolean res = true;
-        
-        // presCond: "M"
-        // Element is mandatory
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
-        if( mandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"M\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( String name : this.mandatory ) {
-                if( presentBDA.get( name ) == null ) {
-                  diagnostics.add( new BasicDiagnostic(
-                          Diagnostic.ERROR,
-                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                          0,
-                          "[NSD validation] BDA" + name + " is mandatory in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                          new Object[] { daType } ));
-                  res = false;
-                }
-            }
-        }
-
-        // presCond: "O"
-        // Element is optional
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
-        if( optional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"O\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( String name : this.optional ) {
-                if( presentBDA.get( name ) == null ) {
-                    // Nothing
-                }
-            }
-        }
 
-        // presCond: "F"
-        // Element is forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( forbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"F\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( String name : this.forbidden ) {
-                if( presentBDA.get( name ) != null ) {
-                  diagnostics.add( new BasicDiagnostic(
-                          Diagnostic.ERROR,
-                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                          0,
-                          "[NSD validation] BDA" + name + " is forbidden in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                          new Object[] { daType } ));
-                  res = false;
-                }
-            }
-        }
+    @Override
+    protected String getNsdComponentClassName() {
+        return "SubDataAttribute";
+    }
 
-        // presCond: "na"
-        // Element is not applicable
-        // Usage in standard NSD files (version 2007B): only for dsPresCond
-        // -> TODO: what does it mean ? what do we have to check ?
-        if( notApplicable != null ) {
-            for( String name : notApplicable ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"na\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-        
-        // presCond: "Mmulti"
-        // At least one element shall be present; all instances have an instance number > 0
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryMulti != null ) {
-            for( String name : mandatoryMulti ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"Mmulti\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
+    @Override
+    protected String getSclModelClassName() {
+        return "DAType";
+    }
 
-        // presCond: "Omulti"
-        // Zero or more elements may be present; all instances have an instance number > 0
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalMulti != null ) {
-            for( String name : optionalMulti ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"Omulti\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-        
-        // presCond: "AtLeastOne"
-        // Parameter n: group number (> 0).
-        // At least one of marked elements of a group n shall be present
-        // Usage in standard NSD files (version 2007B): DataObject and SubDataObject and DataAttribute and SubDataAttribute
-        if( atLeastOne != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtLeastOne\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) {
-                boolean groupOK = false;
-                for( String member : e1.getValue() ) {
-                    if( presentBDA.get( member ) != null ) {
-                        groupOK = true;
-                        break;
-                    }
-                }
-                if( ! groupOK ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has no elements in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                    res = false;
-                }
-            }
-        }
-        
-        // presCond: "AtMostOne" :
-        // At most one of marked elements shall be present
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( atMostOne != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtMostOne\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            int count = 0;
-            for( String s : atMostOne ) {
-                if( presentBDA.get( s ) != null ) {
-                    ++count;
-                }
-            }
-            if( count > 1 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] LNodeType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has more than one element marked AtMostOne",
-                        new Object[] { daType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "AllOrNonePerGroup" :
-        // Parameter n: group number (> 0).
-        // All or none of the elements of a group n shall be present
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( allOrNonePerGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOrNonePerGroup\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentBDA.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                    res = false;
-                }
-            }
-        }
-        
-        // presCond: "AllOnlyOneGroup" :
-        // Parameter n: group number (> 0).
-        // All elements of only one group n shall be present
-        // Usage in standard NSD files (version 2007B): DataObject and SubDataAttribute
-        if( allOnlyOneGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOnlyOneGroup\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            int groupNumber = 0;
-            for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentBDA.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                    res = false;
-                }
-                else if( groupCount > 0 ) {
-                    if( groupNumber == 0 ) {
-                        groupNumber = e1.getKey();
-                    }
-                    else {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] LNodeType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has several groups with all elements",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-            }
-            if( groupNumber == 0 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] no group in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has all elements",
-                        new Object[] { daType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "AllAtLeastOneGroup" :
-        // Parameter n: group number (> 0).
-        // All elements of at least one group n shall be present
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( allAtLeastOneGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllAtLeastOneGroup\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            int groupNumber = 0;
-            for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentBDA.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if( groupCount == e1.getValue().size() ) {
-                    groupNumber = e1.getKey();
-                }
-            }
-            if( groupNumber == 0 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] no group in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has all elements",
-                        new Object[] { daType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "MF" :
-        // Parameter sibling: sibling element name.
-        // Mandatory if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfSiblingPresentElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MF\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
-                if( presentBDA.get( entry.getValue() ) != null ) {
-                    if( presentBDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-                else {
-                    if( presentBDA.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is forbidden in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "MO" :
-        // Parameter sibling: sibling element name.
-        // Mandatory if sibling element is present, otherwise optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryIfSiblingPresentElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MO\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
-                if( presentBDA.get( entry.getValue() ) != null ) {
-                    if( presentBDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "OM" :
-        // Parameter sibling: sibling element name.
-        // Optional if sibling element is present, otherwise mandatory
-        // Usage in standard NSD files (version 2007B): None
-        if( optionalIfSiblingPresentElseMandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OM\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) {
-                if( presentBDA.get( entry.getValue() ) == null ) {
-                    if( presentBDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "FM" :
-        // Parameter sibling: sibling element name.
-        // Forbidden if sibling element is present, otherwise mandatory
-        // Usage in standard NSD files (version 2007B): None
-        if( forbiddenIfSiblingPresentElseMandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"FM\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
-                if( presentBDA.get( entry.getValue() ) != null ) {
-                    if( presentBDA.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is forbidden in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-                else {
-                    if( presentBDA.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "MOcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is mandatory, otherwise optional
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfTextConditionElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOcond\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) {
-                String doc = constructedAttribute
-                        .getSubDataAttribute()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
+    @Override
+    protected String getSclComponentClassName() {
+        return "BDA";
+    }
 
+    @Override
+    protected boolean validateMFln0( DAType sclModel, DiagnosticChain diagnostics ) {
+        for( String name : mandatoryInLLN0ElseForbidden ) {
+            if( presentSclComponent.get( name ) != null ) {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute "
-                                + constructedAttribute.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is "
-                                + ( presentBDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { daType } ));
+                        "[NSD validation] verification of PresenceCondition \"MFln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                        new Object[] { sclModel } ));
             }
         }
-        
-        // presCond: "MFcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is mandatory, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfTextConditionElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFcond\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) {
-                String doc = constructedAttribute
-                        .getSubDataAttribute()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
+        return true;
+    }
 
+    @Override
+    protected boolean validateMOln0( DAType sclModel, DiagnosticChain diagnostics ) {
+        for( String name : mandatoryInLLN0ElseOptional ) {
+            if( presentSclComponent.get( name ) != null ) {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute "
-                                + constructedAttribute.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
-                                + ( presentBDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { daType } ));
+                        "[NSD validation] verification of PresenceCondition \"MOln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                        new Object[] { sclModel } ));
             }
         }
-        
-        // presCond: "OFcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is optional, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalIfTextConditionElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OFcond\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) {
-                String doc = constructedAttribute
-                        .getSubDataAttribute()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
+        return true;
+    }
 
+    @Override
+    protected boolean validateOMSynPh( DAType sclModel, DiagnosticChain diagnostics ) {
+        for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) {
+            if( presentSclComponent.get( name ) != null ) {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] BDA" + entry.getKey() + " is optional in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute "
-                                + constructedAttribute.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
-                                + ( presentBDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { daType } ));
-            }
-        }
-        
-        // presCond: "MmultiRange" :
-        // Parameters min, max: limits for instance number (> 0).
-        // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-        // Usage in standard NSD files (version 2007B): None
-        if( mandatoryMultiRange != null ) {
-            for( String name : mandatoryMultiRange.keySet() ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MmultiRange\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "OmultiRange" :
-        // Parameters min, max: limits for instance number (> 0).
-        // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalMultiRange != null ) {
-            for( String name : optionalMultiRange.keySet() ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"OmultiRange\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MFsubst" :
-        // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfSubstitutionElseForbidden != null ) {
-            for( String name : mandatoryIfSubstitutionElseForbidden ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFsubst\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-        
-        // presCond: "MOln0" :
-        // Element is mandatory in the context of LLN0; otherwise optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryInLLN0ElseOptional != null ) {
-            for( String name : mandatoryInLLN0ElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOln0\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-        
-        // presCond: "MFln0" :
-        // Element is mandatory in the context of LLN0; otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryInLLN0ElseForbidden != null ) {
-            for( String name : mandatoryInLLN0ElseForbidden ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFln0\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MOlnNs" :
-        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO: The meaning is not clear.
-        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional != null ) {
-            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOlnNs\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
+                        "[NSD validation] verification of PresenceCondition \"OMSynPh\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                        new Object[] { sclModel } ));
             }
         }
-
-        // presCond: "MOdataNs" :
-        // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
-        // otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO: The meaning is not clear.
-        if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional != null ) {
-            for( String name : mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOdataNs\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledAV" :
-        // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
-        // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
-        // the description of scaling remains mandatory for their (SCL) configuration
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfAnalogValueIncludesIElseForbidden != null ) {
-            for( String name : mandatoryIfAnalogValueIncludesIElseForbidden ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledMagV" :
-        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
-        // *See MFscaledAV
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden != null ) {
-            for( String name : mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledAngV" :
-        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
-        // *See MFscaledAV
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden != null ) {
-            for( String name : mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MOrms" :
-        // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
-        // (value of data attribute 'hvRef' is 'rms'), optional otherwise
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional != null ) {
-            for( String name : mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOrms\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MOrootLD" :
-        // Element is mandatory in the context of a root logical device; otherwise it is optional
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryInRootLogicalDeviceElseOptional != null ) {
-            for( String name : mandatoryInRootLogicalDeviceElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOrootLD\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MOoperTm" :
-        // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsTimeElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsTimeElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOoperTm\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MmultiF" :
-        // Parameter sibling: sibling element name.
-        // One or more elements must be present if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        // TODO: One or more elements ? Is there an instance number ?
-        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
-            for( String name : oneOrMoreIfSiblingPresentElseForbidden.keySet() ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MmultiF\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MOsbo" :
-        // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
-        // otherwise optional and value is of no impact
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsSecurity1ElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsSecurity1ElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOsbo\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MOenhanced" :
-        // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
-        // otherwise optional and value is of no impact
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsSecurity2ElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsSecurity2ElseOptional ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOenhanced\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "MONamPlt" :
-        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataObject
-        // TODO: same as "MOlnNs" ?
-        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 != null ) {
-            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MONamPlt\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "OF" :
-        // Parameter sibling: sibling element name.
-        // Optional if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute
-        if( optionalIfSiblingPresentElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OF\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) {
-                if( presentBDA.get( entry.getValue() ) == null ) {
-                    if( presentBDA.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] BDA" + entry.getKey() + " is forbidden in DAType (line " + daType.getLineNumber() + ") with LNClass "
-                                        + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { daType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-
-        // presCond: "MORange" :
-        // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
-        // (with the attribute range respectively rangeAng)
-        // Usage in standard NSD files (version 2007B): SubDataAttribute
-        // TODO
-        if( mandatoryIfMeasuredValueExposesRange != null ) {
-            for( String name : mandatoryIfMeasuredValueExposesRange ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MORange\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        // presCond: "OMSynPh" :
-        // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
-        // Usage in standard NSD files (version 2007B): SubDataObject
-        // TODO
-        if( optionalIfPhsRefIsSynchrophasorElseMandatory != null ) {
-            for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) {
-                if( presentBDA.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"OMSynPh\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(),
-                            new Object[] { daType } ));
-                }
-            }
-        }
-
-        return res;
+        return true;
     }
 
 }
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java
index 7ce4319..64d95c9 100644
--- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java
@@ -19,29 +19,23 @@
 package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd;
 
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map.Entry;
 import java.util.Optional;
 
-import org.apache.commons.lang3.tuple.Pair;
 import org.eclipse.emf.common.util.BasicDiagnostic;
 import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.common.util.DiagnosticChain;
 import org.eclipse.emf.common.util.EList;
+import org.eclipse.jdt.annotation.Nullable;
 
 import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC;
-import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataObject;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
-import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.SDO;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
-import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
-import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole;
 
-public class SubDataObjectPresenceConditionValidator {
-    
+public class SubDataObjectPresenceConditionValidator extends GenericPresenceConditionValidator< CDC, DOType, @Nullable SDO >{
+
     private static HashMap< String, SubDataObjectPresenceConditionValidator > validators = new HashMap<>();
     
     public static SubDataObjectPresenceConditionValidator get( CDC cdc ) {
@@ -52,1411 +46,137 @@ public class SubDataObjectPresenceConditionValidator {
     }
     
     private CDC cdc;
-    
-    // Name of the SubDataObject/SDO, SDO
-    private HashMap< String, SDO > presentSDO = new HashMap<>();
-    
-    private HashSet< String > mandatory;
-    private HashSet< String > optional;
-    private HashSet< String > forbidden;
-    private HashSet< String > notApplicable;
-    private HashSet< String > mandatoryMulti;
-    private HashSet< String > optionalMulti;
-    private HashMap< Integer, HashSet< String > > atLeastOne;
-    private HashSet< String > atMostOne;
-    private HashMap< Integer, HashSet< String > > allOrNonePerGroup;
-    private HashMap< Integer, HashSet< String > > allOnlyOneGroup;
-    private HashMap< Integer, HashSet< String > > allAtLeastOneGroup;
-    private HashMap< String, String > mandatoryIfSiblingPresentElseForbidden;
-    private HashMap< String, String > mandatoryIfSiblingPresentElseOptional;
-    private HashMap< String, String > optionalIfSiblingPresentElseMandatory;
-    private HashMap< String, String > forbiddenIfSiblingPresentElseMandatory;
-    private HashMap< String, String > mandatoryIfTextConditionElseOptional;
-    private HashMap< String, String > mandatoryIfTextConditionElseForbidden;
-    private HashMap< String, String > optionalIfTextConditionElseForbidden;
-    private HashMap< String, Pair< Integer, Integer > > mandatoryMultiRange;
-    private HashMap< String, Pair< Integer, Integer > > optionalMultiRange;
-    private HashSet< String > mandatoryIfSubstitutionElseForbidden;
-    private HashSet< String > mandatoryInLLN0ElseOptional;
-    private HashSet< String > mandatoryInLLN0ElseForbidden;
-    private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional;
-    private HashSet< String > mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional;
-    private HashSet< String > mandatoryIfAnalogValueIncludesIElseForbidden;
-    private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden;
-    private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden;
-    private HashSet< String > mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional;
-    private HashSet< String > mandatoryInRootLogicalDeviceElseOptional;
-    private HashSet< String > mandatoryIfControlSupportsTimeElseOptional;
-    private HashMap< String, String > oneOrMoreIfSiblingPresentElseForbidden;
-    private HashSet< String > mandatoryIfControlSupportsSecurity1ElseOptional;
-    private HashSet< String > mandatoryIfControlSupportsSecurity2ElseOptional;
-    private HashMap< String, String > optionalIfSiblingPresentElseForbidden;
-    private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2;
-    private HashSet< String > mandatoryIfMeasuredValueExposesRange;
-    private HashSet< String > optionalIfPhsRefIsSynchrophasorElseMandatory;
-    
-    private final IRiseClipseConsole console = AbstractRiseClipseConsole.getConsole();
-    
+
     public SubDataObjectPresenceConditionValidator( CDC cdc ) {
-        this.cdc = cdc;
+        super( cdc );
         
+        this.cdc = cdc;
+    }
+
+    @Override
+    protected void createSpecifications( CDC cdc ) {
         cdc
         .getSubDataObject()
         .stream()
-        .forEach( sdo -> addSpecification( sdo.getName(), sdo.getPresCond(), sdo.getPresCondArgs() ) );
-
-        checkSpecification();
+        .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs(), sda.getRefersToPresCondArgsDoc() ));
     }
-    
-    public void reset() {
-        for( String sdo : presentSDO.keySet() ) {
-            presentSDO.put( sdo, null );
-        }
-    }
-    
-    private void addSpecification( String name, String presCond, String presCondArgs ) {
-        if( presentSDO.containsKey( name )) {
-            console.warning( "[NSD setup] " + name + " has already been added to SubDataObjectPresenceConditionValidator" );
-            return;
-        }
-        presentSDO.put( name, null );
 
-        switch( presCond ) {
-        case "M" :
-            // Element is mandatory
-            if( mandatory == null ) mandatory = new HashSet<>();
-            mandatory.add( name );
-            break;
-        case "O" :
-            // Element is optional
-            if( optional == null ) optional = new HashSet<>();
-            optional.add( name );
-            break;
-        case "F" :
-            // Element is forbidden
-            if( forbidden == null ) forbidden = new HashSet<>();
-            forbidden.add( name );
-            break;
-        case "na" :
-            // Element is not applicable
-            // -> TODO: what does it mean ? what do we have to check ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"na\" in PresenceCondition" );
-            if( notApplicable == null ) notApplicable = new HashSet<>();
-            notApplicable.add( name );
-            break;
-        case "Mmulti" :
-            // At least one element shall be present; all instances have an instance number > 0
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"Mmulti\" in PresenceCondition" );
-            if( mandatoryMulti == null ) mandatoryMulti = new HashSet<>();
-            mandatoryMulti.add( name );
-            break;
-        case "Omulti" :
-            // Zero or more elements may be present; all instances have an instance number > 0
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"Omulti\" in PresenceCondition" );
-            if( optionalMulti == null ) optionalMulti = new HashSet<>();
-            optionalMulti.add( name );
-            break;
-        case "AtLeastOne" :
-            // Parameter n: group number (> 0).
-            // At least one of marked elements of a group n shall be present
-            if( atLeastOne == null ) atLeastOne = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not a positive integer" );
-                    break;
-                }
-                if( ! atLeastOne.containsKey( arg )) {
-                    atLeastOne.put( arg, new HashSet<>() );
-                }
-                atLeastOne.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not an integer" );
-                break;
-            }
-        case "AtMostOne" :
-            // At most one of marked elements shall be present
-            if( atMostOne == null ) atMostOne = new HashSet<>();
-            atMostOne.add( name );
-            break;
-        case "AllOrNonePerGroup" :
-            // Parameter n: group number (> 0).
-            // All or none of the elements of a group n shall be present
-            if( allOrNonePerGroup == null ) allOrNonePerGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allOrNonePerGroup.containsKey( arg )) {
-                    allOrNonePerGroup.put( arg, new HashSet<>() );
-                }
-                allOrNonePerGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not an integer" );
-                break;
-            }
-        case "AllOnlyOneGroup" :
-            // Parameter n: group number (> 0).
-            // All elements of only one group n shall be present
-            if( allOnlyOneGroup == null ) allOnlyOneGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allOnlyOneGroup.containsKey( arg )) {
-                    allOnlyOneGroup.put( arg, new HashSet<>() );
-                }
-                allOnlyOneGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not an integer" );
-                break;
-            }
-        case "AllAtLeastOneGroup" :
-            // Parameter n: group number (> 0).
-            // All elements of at least one group n shall be present
-            if( allAtLeastOneGroup == null ) allAtLeastOneGroup = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not a positive integer" );
-                    break;
-                }
-                if( ! allAtLeastOneGroup.containsKey( arg )) {
-                    allAtLeastOneGroup.put( arg, new HashSet<>() );
-                }
-                allAtLeastOneGroup.get( arg ).add( name );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not an integer" );
-                break;
-            }
-        case "MF" :
-            // Parameter sibling: sibling element name.
-            // Mandatory if sibling element is present, otherwise forbidden
-            if( mandatoryIfSiblingPresentElseForbidden == null ) mandatoryIfSiblingPresentElseForbidden = new HashMap<>();
-            mandatoryIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MO" :
-            // Parameter sibling: sibling element name.
-            // Mandatory if sibling element is present, otherwise optional
-            if( mandatoryIfSiblingPresentElseOptional == null ) mandatoryIfSiblingPresentElseOptional = new HashMap<>();
-            mandatoryIfSiblingPresentElseOptional.put( name, presCondArgs );
-            break;
-        case "OM" :
-            // Parameter sibling: sibling element name.
-            // Optional if sibling element is present, otherwise mandatory
-            if( optionalIfSiblingPresentElseMandatory == null ) optionalIfSiblingPresentElseMandatory = new HashMap<>();
-            optionalIfSiblingPresentElseMandatory.put( name, presCondArgs );
-            break;
-        case "FM" :
-            // Parameter sibling: sibling element name.
-            // Forbidden if sibling element is present, otherwise mandatory
-            if( forbiddenIfSiblingPresentElseMandatory == null ) forbiddenIfSiblingPresentElseMandatory = new HashMap<>();
-            forbiddenIfSiblingPresentElseMandatory.put( name, presCondArgs );
-            break;
-        case "MOcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is mandatory, otherwise optional
-            if( mandatoryIfTextConditionElseOptional == null ) mandatoryIfTextConditionElseOptional = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not a positive integer" );
-                    break;
-                }
-                mandatoryIfTextConditionElseOptional.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not an integer" );
-                break;
-            }
-        case "MFcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is mandatory, otherwise forbidden
-            if( mandatoryIfTextConditionElseForbidden == null ) mandatoryIfTextConditionElseForbidden = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
-                    break;
-                }
-                mandatoryIfTextConditionElseForbidden.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
-                break;
-            }
-        case "OFcond" :
-            // Parameter condID: condition number (> 0).
-            // Textual presence condition (non-machine processable) with reference condID to context specific text.
-            // If satisfied, the element is optional, otherwise forbidden
-            if( optionalIfTextConditionElseForbidden == null ) optionalIfTextConditionElseForbidden = new HashMap<>();
-            try {
-                Integer arg = Integer.valueOf( presCondArgs );
-                if( arg <= 0 ) {
-                    console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" );
-                    break;
-                }
-                optionalIfTextConditionElseForbidden.put( name, presCondArgs );
-                break;
-            }
-            catch( NumberFormatException e ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" );
-                break;
-            }
-        case "MmultiRange" :
-            // Parameters min, max: limits for instance number (> 0).
-            // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MmultiRange\" in PresenceCondition" );
-            if( mandatoryMultiRange == null ) mandatoryMultiRange = new HashMap<>();
-            String[] limits1 = presCondArgs.split( "[ ,]+" );
-            if( limits1.length != 2 ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"MmultiRange\" is not two integers" );
-                break;
-            }
-            Integer min1 = Integer.valueOf( limits1[0] );
-            if( min1 <= 0 ) {
-                console.warning( "[NSD setup] first argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
-                break;
-            }
-            Integer max1 = Integer.valueOf( limits1[1] );
-            if( max1 <= 0 ) {
-                console.warning( "[NSD setup] second argument of PresenceCondition \"MmultiRange\" is not a positive integer" );
-                break;
-            }
-            mandatoryMultiRange.put( name, Pair.of( min1, max1 ));
-            break;
-        case "OmultiRange" :
-            // Parameters min, max: limits for instance number (> 0).
-            // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-            // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"OmultiRange\" in PresenceCondition" );
-            if( optionalMultiRange == null ) optionalMultiRange = new HashMap<>();
-            String[] limits2 = presCondArgs.split( "[ ,]+" );
-            if( limits2.length != 2 ) {
-                console.warning( "[NSD setup] argument of PresenceCondition \"OmultiRange\" is not two integers" );
-                break;
-            }
-            Integer min2 = Integer.valueOf( limits2[0] );
-            if( min2 <= 0 ) {
-                console.warning( "[NSD setup] first argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
-                break;
-            }
-            Integer max2 = Integer.valueOf( limits2[1] );
-            if( max2 <= 0 ) {
-                console.warning( "[NSD setup] second argument of PresenceCondition \"OmultiRange\" is not a positive integer" );
-                break;
-            }
-            optionalMultiRange.put( name, Pair.of( min2, max2 ));
-            break;
-        case "MFsubst" :
-            // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
-            // TODO: how do we know if substitution is supported ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MFsubst\" in PresenceCondition" );
-            if( mandatoryIfSubstitutionElseForbidden == null ) mandatoryIfSubstitutionElseForbidden = new HashSet<>();
-            mandatoryIfSubstitutionElseForbidden.add( name );
-            break;
-        case "MOln0" :
-            // Element is mandatory in the context of LLN0; otherwise optional
-            if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>();
-            mandatoryInLLN0ElseOptional.add( name );
-            break;
-        case "MFln0" :
-            // Element is mandatory in the context of LLN0; otherwise forbidden
-            if( mandatoryInLLN0ElseForbidden == null ) mandatoryInLLN0ElseForbidden = new HashSet<>();
-            mandatoryInLLN0ElseForbidden.add( name );
-            break;
-        case "MOlnNs" :
-            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOlnNs\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional = new HashSet<>();
-            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional.add( name );
-            break;
-        case "MOdataNs" :
-            // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
-            // otherwise optional. See IEC 61850-7-1 for use of name space
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOdataNs\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional == null ) mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional = new HashSet<>();
-            mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional.add( name );
-            break;
-        case "MFscaledAV" :
-            // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
-            // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
-            // the description of scaling remains mandatory for their (SCL) configuration
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MFscaledAV\" in PresenceCondition" );
-            if( mandatoryIfAnalogValueIncludesIElseForbidden == null ) mandatoryIfAnalogValueIncludesIElseForbidden = new HashSet<>();
-            mandatoryIfAnalogValueIncludesIElseForbidden.add( name );
-            break;
-        case "MFscaledMagV" :
-            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
-            // *See MFscaledAV
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MFscaledMagV\" in PresenceCondition" );
-            if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden = new HashSet<>();
-            mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden.add( name );
-            break;
-        case "MFscaledAngV" :
-            // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
-            // *See MFscaledAV
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MFscaledAngV\" in PresenceCondition" );
-            if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden = new HashSet<>();
-            mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden.add( name );
-            break;
-        case "MOrms" :
-            // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
-            // (value of data attribute 'hvRef' is 'rms'), optional otherwise
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOrms\" in PresenceCondition" );
-            if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional == null ) mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional = new HashSet<>();
-            mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional.add( name );
-            break;
-        case "MOrootLD" :
-            // Element is mandatory in the context of a root logical device; otherwise it is optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOrootLD\" in PresenceCondition" );
-            if( mandatoryInRootLogicalDeviceElseOptional == null ) mandatoryInRootLogicalDeviceElseOptional = new HashSet<>();
-            mandatoryInRootLogicalDeviceElseOptional.add( name );
-            break;
-        case "MOoperTm" :
-            // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOoperTm\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsTimeElseOptional == null ) mandatoryIfControlSupportsTimeElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsTimeElseOptional.add( name );
-            break;
-        case "MmultiF" :
-            // Parameter sibling: sibling element name.
-            // One or more elements must be present if sibling element is present, otherwise forbidden
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MmultiF\" in PresenceCondition" );
-            if( oneOrMoreIfSiblingPresentElseForbidden == null ) oneOrMoreIfSiblingPresentElseForbidden = new HashMap<>();
-            oneOrMoreIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MOsbo" :
-            // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
-            // otherwise optional and value is of no impact
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOsbo\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsSecurity1ElseOptional == null ) mandatoryIfControlSupportsSecurity1ElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsSecurity1ElseOptional.add( name );
-            break;
-        case "MOenhanced" :
-            // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
-            // otherwise optional and value is of no impact
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MOenhanced\" in PresenceCondition" );
-            if( mandatoryIfControlSupportsSecurity2ElseOptional == null ) mandatoryIfControlSupportsSecurity2ElseOptional = new HashSet<>();
-            mandatoryIfControlSupportsSecurity2ElseOptional.add( name );
-            break;
-        case "MONamPlt" :
-            // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-            // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-            // TODO: same as "MOlnNs" ?
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MONamPlt\" in PresenceCondition" );
-            if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 = new HashSet<>();
-            mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2.add( name );
-            break;
-        case "OF" :
-            // Parameter sibling: sibling element name.
-            // Optional if sibling element is present, otherwise forbidden
-            if( optionalIfSiblingPresentElseForbidden == null ) optionalIfSiblingPresentElseForbidden = new HashMap<>();
-            optionalIfSiblingPresentElseForbidden.put( name, presCondArgs );
-            break;
-        case "MORange" :
-            // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
-            // (with the attribute range respectively rangeAng)
-            console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataObject " + name + " declared as \"MORange\" in PresenceCondition" );
-            if( mandatoryIfMeasuredValueExposesRange == null ) mandatoryIfMeasuredValueExposesRange = new HashSet<>();
-            mandatoryIfMeasuredValueExposesRange.add( name );
-            break;
-        case "OMSynPh" :
-            // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory
-            if( optionalIfPhsRefIsSynchrophasorElseMandatory == null ) optionalIfPhsRefIsSynchrophasorElseMandatory = new HashSet<>();
-            optionalIfPhsRefIsSynchrophasorElseMandatory.add( name );
-            break;
-        default:
-            console.warning( "[NSD setup] the PresenceCondition " + presCond + " of AnyLNClass " + name + " is unknown" );
-            break;
-        }
-        
-    }
-    
-    private void checkSpecification() {
-        // TODO: do we have to check the presence of the sibling in inherited AbstractLNClass ?
-        if( mandatoryIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentSDO.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( mandatoryIfSiblingPresentElseOptional != null ) {
-            for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
-                if( ! presentSDO.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( optionalIfSiblingPresentElseMandatory != null ) {
-            for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) {
-                if( ! presentSDO.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( forbiddenIfSiblingPresentElseMandatory != null ) {
-            for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
-                if( ! presentSDO.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentSDO.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" );
-                }
-            }
-        }
-        if( optionalIfSiblingPresentElseForbidden != null ) {
-            for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) {
-                if( ! presentSDO.containsKey( e.getValue() )) {
-                    console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" );
-                }
-            }
-        }
+    @Override
+    protected String getPresenceConditionValidatorName() {
+        return "SubDataObjectPresenceConditionValidator";
     }
 
-    public boolean addSDO( SDO sdo, DiagnosticChain diagnostics ) {
-        if( ! presentSDO.containsKey( sdo.getName() )) {
-            diagnostics.add( new BasicDiagnostic(
-                    Diagnostic.ERROR,
-                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                    0,
-                    "[NSD validation] SDO " + sdo.getName() + " in DOType (line " + sdo.getParentDOType().getLineNumber() + ") not found in CDC " + cdc.getName(),
-                    new Object[] { sdo } ));
-            return false;
-        }
-
-        if( presentSDO.get( sdo.getName() ) != null ) {
-            diagnostics.add( new BasicDiagnostic(
-                    Diagnostic.ERROR,
-                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                    0,
-                    "[NSD validation] SDO " + sdo.getName() + " in DOType (line " + sdo.getParentDOType().getLineNumber() + ") already present in CDC " + cdc.getName(),
-                    new Object[] { sdo } ));
-            return false;
-        }
-        presentSDO.put( sdo.getName(), sdo );
-        return true;
+    @Override
+    protected String getNsdModelName() {
+        return cdc.getName();
     }
-    
-    public boolean validate( DOType doType, DiagnosticChain diagnostics ) {
-        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] SubDataObjectPresenceConditionValidator.validate( " + doType.getId() + ") at line " + doType.getLineNumber() );
 
-        boolean res = true;
-        
-        // presCond: "M"
-        // Element is mandatory
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
-        if( mandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"M\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( String name : this.mandatory ) {
-                if( presentSDO.get( name ) == null ) {
-                  diagnostics.add( new BasicDiagnostic(
-                          Diagnostic.ERROR,
-                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                          0,
-                          "[NSD validation] SDO " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                          new Object[] { doType } ));
-                  res = false;
-                }
-            }
-        }
+    @Override
+    protected String getNsdModelClassName() {
+        return "CDC";
+    }
 
-        // presCond: "O"
-        // Element is optional
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute
-        if( optional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"O\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( String name : this.optional ) {
-                if( presentSDO.get( name ) == null ) {
-                    // Nothing
-                }
-            }
-        }
+    @Override
+    protected String getNsdComponentClassName() {
+        return "SubDataObject";
+    }
 
-        // presCond: "F"
-        // Element is forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( forbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"F\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( String name : this.forbidden ) {
-                if( presentSDO.get( name ) != null ) {
-                  diagnostics.add( new BasicDiagnostic(
-                          Diagnostic.ERROR,
-                          RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                          0,
-                          "[NSD validation] SDO " + name + " is forbidden in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                          new Object[] { doType } ));
-                  res = false;
-                }
-            }
-        }
+    @Override
+    protected String getSclModelClassName() {
+        return "DOType";
+    }
 
-        // presCond: "na"
-        // Element is not applicable
-        // Usage in standard NSD files (version 2007B): only for dsPresCond
-        // -> TODO: what does it mean ? what do we have to check ?
-        if( notApplicable != null ) {
-            for( String name : notApplicable ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"na\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-        
-        // presCond: "Mmulti"
-        // At least one element shall be present; all instances have an instance number > 0
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryMulti != null ) {
-            for( String name : mandatoryMulti ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"Mmulti\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
+    @Override
+    protected String getSclComponentClassName() {
+        return "SDO";
+    }
 
-        // presCond: "Omulti"
-        // Zero or more elements may be present; all instances have an instance number > 0
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalMulti != null ) {
-            for( String name : optionalMulti ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"Omulti\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-        
-        // presCond: "AtLeastOne"
-        // Parameter n: group number (> 0).
-        // At least one of marked elements of a group n shall be present
-        // Usage in standard NSD files (version 2007B): DataObject and SubDataObject and DataAttribute and SubDataAttribute
-        if( atLeastOne != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtLeastOne\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) {
-                boolean groupOK = false;
-                for( String member : e1.getValue() ) {
-                    if( presentSDO.get( member ) != null ) {
-                        groupOK = true;
-                        break;
-                    }
-                }
-                if( ! groupOK ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has no elements in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                    res = false;
-                }
-            }
-        }
-        
-        // presCond: "AtMostOne" :
-        // At most one of marked elements shall be present
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( atMostOne != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtMostOne\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            int count = 0;
-            for( String s : atMostOne ) {
-                if( presentSDO.get( s ) != null ) {
-                    ++count;
-                }
-            }
-            if( count > 1 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] LNodeType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has more than one element marked AtMostOne",
-                        new Object[] { doType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "AllOrNonePerGroup" :
-        // Parameter n: group number (> 0).
-        // All or none of the elements of a group n shall be present
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( allOrNonePerGroup != null ) {
-            for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) {
-                AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOrNonePerGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentSDO.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                    res = false;
-                }
-            }
-        }
-        
-        // presCond: "AllOnlyOneGroup" :
-        // Parameter n: group number (> 0).
-        // All elements of only one group n shall be present
-        // Usage in standard NSD files (version 2007B): DataObject and SubDataAttribute
-        if( allOnlyOneGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOnlyOneGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            int groupNumber = 0;
-            for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentSDO.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.ERROR,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                    res = false;
-                }
-                else if( groupCount > 0 ) {
-                    if( groupNumber == 0 ) {
-                        groupNumber = e1.getKey();
-                    }
-                    else {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] LNodeType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has several groups with all elements",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-            if( groupNumber == 0 ) {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements",
-                        new Object[] { doType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "AllAtLeastOneGroup" :
-        // Parameter n: group number (> 0).
-        // All elements of at least one group n shall be present
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( allAtLeastOneGroup != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllAtLeastOneGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            int groupNumber = 0;
-            for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) {
-                int groupCount = 0;
-                for( String member : e1.getValue() ) {
-                    if( presentSDO.get( member ) != null ) {
-                        ++groupCount;
-                    }
-                }
-                if( groupCount == e1.getValue().size() ) {
-                    groupNumber = e1.getKey();
-                }
-            }
-            if( groupNumber == 0 ) {
+    @Override
+    protected boolean validateMFln0( DOType sclModel, DiagnosticChain diagnostics ) {
+        for( String name : mandatoryInLLN0ElseForbidden ) {
+            if( presentSclComponent.get( name ) != null ) {
                 diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.ERROR,
+                        Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements",
-                        new Object[] { doType } ));
-                res = false;
-            }
-        }
-        
-        // presCond: "MF" :
-        // Parameter sibling: sibling element name.
-        // Mandatory if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfSiblingPresentElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"<<<<<<<<mf\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) {
-                if( presentSDO.get( entry.getValue() ) != null ) {
-                    if( presentSDO.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-                else {
-                    if( presentSDO.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "MO" :
-        // Parameter sibling: sibling element name.
-        // Mandatory if sibling element is present, otherwise optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryIfSiblingPresentElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MO\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) {
-                if( presentSDO.get( entry.getValue() ) != null ) {
-                    if( presentSDO.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "OM" :
-        // Parameter sibling: sibling element name.
-        // Optional if sibling element is present, otherwise mandatory
-        // Usage in standard NSD files (version 2007B): None
-        if( optionalIfSiblingPresentElseMandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OM\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) {
-                if( presentSDO.get( entry.getValue() ) == null ) {
-                    if( presentSDO.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-        
-        // presCond: "FM" :
-        // Parameter sibling: sibling element name.
-        // Forbidden if sibling element is present, otherwise mandatory
-        // Usage in standard NSD files (version 2007B): None
-        if( forbiddenIfSiblingPresentElseMandatory != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"FM\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) {
-                if( presentSDO.get( entry.getValue() ) != null ) {
-                    if( presentSDO.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-                else {
-                    if( presentSDO.get( entry.getKey() ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
+                        "[NSD validation] verification of PresenceCondition \"MFln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                        new Object[] { sclModel } ));
             }
         }
-        
-        // presCond: "MOcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is mandatory, otherwise optional
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfTextConditionElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOcond\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) {
-                String doc = cdc
-                        .getSubDataObject()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
+        return true;
+    }
 
+    @Override
+    protected boolean validateMOln0( DOType sclModel, DiagnosticChain diagnostics ) {
+        for( String name : mandatoryInLLN0ElseOptional ) {
+            if( presentSclComponent.get( name ) != null ) {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC "
-                                + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is "
-                                + ( presentSDO.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
-                        new Object[] { doType } ));
+                        "[NSD validation] verification of PresenceCondition \"MOln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(),
+                        new Object[] { sclModel } ));
             }
         }
-        
-        // presCond: "MFcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is mandatory, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryIfTextConditionElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFcond\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) {
-                String doc = cdc
-                        .getSubDataObject()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
+        return true;
+    }
 
+    @Override
+    protected boolean validateOMSynPh( DOType doType, DiagnosticChain diagnostics ) {
+        boolean res = true;
+        
+        String sdoName = optionalIfPhsRefIsSynchrophasorElseMandatory.stream().findFirst().get();
+        boolean phsRefIsSynchrophasor = false;
+        Optional< DA > phsRef = doType
+                .getDA()
+                .stream()
+                .filter( da -> "phsRef".equals( da.getName() ))
+                .findAny();
+        if( phsRef.isPresent() ) {
+            EList< Val > vals = phsRef.get().getVal();
+            if( vals.size() == 0 ) {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC "
-                                + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
-                                + ( presentSDO.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
+                        "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): no value for phsRef",
                         new Object[] { doType } ));
             }
-        }
-        
-        // presCond: "OFcond" :
-        // Parameter condID: condition number (> 0).
-        // Textual presence condition (non-machine processable) with reference condID to context specific text.
-        // If satisfied, the element is optional, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalIfTextConditionElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OFcond\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) {
-                String doc = cdc
-                        .getSubDataObject()
-                        .stream()
-                        .filter( d -> d.getName().equals( entry.getKey() ))
-                        .findFirst()
-                        .map( x -> x.getRefersToPresCondArgsDoc() )
-                        .map( p -> p.getMixed() )
-                        .map( p -> p.get( 0 ) )
-                        .map( p -> p.getValue() )
-                        .map( p -> p.toString() )
-                        .orElse( null );
-
+            else if( vals.size() == 1 ) {
+                phsRefIsSynchrophasor = "Synchrophasor".equals( vals.get( 0 ).getValue() );
+            }
+            else {
                 diagnostics.add( new BasicDiagnostic(
                         Diagnostic.WARNING,
                         RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                         0,
-                        "[NSD validation] SDO " + entry.getKey() + " is optional in DOType (line " + doType.getLineNumber() + ") with CDC "
-                                + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " 
-                                + ( presentSDO.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ),
+                        "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): multiple values for phsRef",
                         new Object[] { doType } ));
             }
         }
-        
-        // presCond: "MmultiRange" :
-        // Parameters min, max: limits for instance number (> 0).
-        // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-        // Usage in standard NSD files (version 2007B): None
-        if( mandatoryMultiRange != null ) {
-            for( String name : mandatoryMultiRange.keySet() ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MmultiRange\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "OmultiRange" :
-        // Parameters min, max: limits for instance number (> 0).
-        // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1)
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( optionalMultiRange != null ) {
-            for( String name : optionalMultiRange.keySet() ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"OmultiRange\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFsubst" :
-        // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfSubstitutionElseForbidden != null ) {
-            for( String name : mandatoryIfSubstitutionElseForbidden ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFsubst\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-        
-        // presCond: "MOln0" :
-        // Element is mandatory in the context of LLN0; otherwise optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryInLLN0ElseOptional != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject();
-            for( AbstractDataObject ado : adoList ) {
-                if( ado instanceof DO ) {
-                    DO do_ = ( DO ) ado;
-                    if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) {
-                        for( String attribute : mandatoryInLLN0ElseOptional ) {
-                            SDO sdo = presentSDO.get( attribute );
-                            if( sdo == null ) {
-                                diagnostics.add( new BasicDiagnostic(
-                                        Diagnostic.ERROR,
-                                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                        0,
-                                        "[NSD validation] SDO " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0",
-                                        new Object[] { doType } ));
-                                res = false;
-                            }
-                        }
-                    }
-                }
-                else {
-                    // ado instanceof SDO
-                }
-            }
-        }
-        
-        // presCond: "MFln0" :
-        // Element is mandatory in the context of LLN0; otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        if( mandatoryInLLN0ElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject();
-            for( AbstractDataObject ado : adoList ) {
-                if( ado instanceof DO ) {
-                    DO do_ = ( DO ) ado;
-                    if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) {
-                        for( String attribute : mandatoryInLLN0ElseForbidden ) {
-                            SDO sdo = presentSDO.get( attribute );
-                            if( sdo == null ) {
-                                diagnostics.add( new BasicDiagnostic(
-                                        Diagnostic.ERROR,
-                                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                        0,
-                                        "[NSD validation] SDO " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0",
-                                        new Object[] { doType } ));
-                                res = false;
-                            }
-                        }
-                    }
-                    else {
-                        for( String attribute : mandatoryInLLN0ElseForbidden ) {
-                            SDO sdo = presentSDO.get( attribute );
-                            if( sdo != null ) {
-                                diagnostics.add( new BasicDiagnostic(
-                                        Diagnostic.ERROR,
-                                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                        0,
-                                        "[NSD validation] SDO " + attribute + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " + do_.getParentLNodeType().getLnClass(),
-                                        new Object[] { doType } ));
-                                res = false;
-                            }
-                        }
-                    }
-                }
-                else {
-                    // ado instanceof SDO
-                }
-            }
-        }
-
-        // presCond: "MOlnNs" :
-        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO: The meaning is not clear.
-        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional != null ) {
-            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOlnNs\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOdataNs" :
-        // Element is mandatory if the name space of its data object deviates from the name space of its logical node,
-        // otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO: The meaning is not clear.
-        if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional != null ) {
-            for( String name : mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOdataNs\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledAV" :
-        // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden.
-        // *Even though devices without floating point capability cannot exchange floating point values through ACSI services,
-        // the description of scaling remains mandatory for their (SCL) configuration
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfAnalogValueIncludesIElseForbidden != null ) {
-            for( String name : mandatoryIfAnalogValueIncludesIElseForbidden ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledMagV" :
-        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden.
-        // *See MFscaledAV
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden != null ) {
-            for( String name : mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MFscaledAngV" :
-        // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden.
-        // *See MFscaledAV
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden != null ) {
-            for( String name : mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOrms" :
-        // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value
-        // (value of data attribute 'hvRef' is 'rms'), optional otherwise
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional != null ) {
-            for( String name : mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOrms\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOrootLD" :
-        // Element is mandatory in the context of a root logical device; otherwise it is optional
-        // Usage in standard NSD files (version 2007B): DataObject
-        if( mandatoryInRootLogicalDeviceElseOptional != null ) {
-            for( String name : mandatoryInRootLogicalDeviceElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOrootLD\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOoperTm" :
-        // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsTimeElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsTimeElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOoperTm\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MmultiF" :
-        // Parameter sibling: sibling element name.
-        // One or more elements must be present if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject
-        // TODO: One or more elements ? Is there an instance number ?
-        if( oneOrMoreIfSiblingPresentElseForbidden != null ) {
-            for( String name : oneOrMoreIfSiblingPresentElseForbidden.keySet() ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MmultiF\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOsbo" :
-        // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security',
-        // otherwise optional and value is of no impact
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsSecurity1ElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsSecurity1ElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOsbo\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MOenhanced" :
-        // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security',
-        // otherwise optional and value is of no impact
-        // Usage in standard NSD files (version 2007B): DataAttribute
-        // TODO
-        if( mandatoryIfControlSupportsSecurity2ElseOptional != null ) {
-            for( String name : mandatoryIfControlSupportsSecurity2ElseOptional ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MOenhanced\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "MONamPlt" :
-        // Element is mandatory if the name space of its logical node deviates from the name space of the containing
-        // logical device, otherwise optional. See IEC 61850-7-1 for use of name space
-        // Usage in standard NSD files (version 2007B): DataObject
-        // TODO: same as "MOlnNs" ?
-        if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 != null ) {
-            for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MONamPlt\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
-        }
-
-        // presCond: "OF" :
-        // Parameter sibling: sibling element name.
-        // Optional if sibling element is present, otherwise forbidden
-        // Usage in standard NSD files (version 2007B): DataObject and DataAttribute
-        if( optionalIfSiblingPresentElseForbidden != null ) {
-            AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OF\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() );
-            for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) {
-                if( presentSDO.get( entry.getValue() ) == null ) {
-                    if( presentSDO.get( entry.getKey() ) != null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass "
-                                        + cdc.getName() + " because sibling " + entry.getValue() + " is not present",
-                                new Object[] { doType } ));
-                        res = false;
-                    }
-                }
-            }
-        }
-
-        // presCond: "MORange" :
-        // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing
-        // (with the attribute range respectively rangeAng)
-        // Usage in standard NSD files (version 2007B): SubDataAttribute
-        // TODO
-        if( mandatoryIfMeasuredValueExposesRange != null ) {
-            for( String name : mandatoryIfMeasuredValueExposesRange ) {
-                if( presentSDO.get( name ) != null ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"MORange\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(),
-                            new Object[] { doType } ));
-                }
-            }
+        else {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.WARNING,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): DA phsRef not found",
+                    new Object[] { doType } ));
         }
-
-        // presCond: "OMSynPh" :
-        // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc>
-        // Usage in standard NSD files (version 2007B): SubDataObject
-        // TODO
-        if( optionalIfPhsRefIsSynchrophasorElseMandatory != null ) {
-            String sdoName = optionalIfPhsRefIsSynchrophasorElseMandatory.stream().findFirst().get();
-            boolean phsRefIsSynchrophasor = false;
-            Optional< DA > phsRef = doType
-                    .getDA()
-                    .stream()
-                    .filter( da -> "phsRef".equals( da.getName() ))
-                    .findAny();
-            if( phsRef.isPresent() ) {
-                EList< Val > vals = phsRef.get().getVal();
-                if( vals.size() == 0 ) {
-                    diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
-                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                            0,
-                            "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): no value for phsRef",
-                            new Object[] { doType } ));
-                }
-                else if( vals.size() == 1 ) {
-                    phsRefIsSynchrophasor = "Synchrophasor".equals( vals.get( 0 ).getValue() );
-                }
-                else {
+        if( ! phsRefIsSynchrophasor ) {
+            for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) {
+                if( presentSclComponent.get( name ) == null ) {
                     diagnostics.add( new BasicDiagnostic(
-                            Diagnostic.WARNING,
+                            Diagnostic.ERROR,
                             RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
                             0,
-                            "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): multiple values for phsRef",
+                            "[NSD validation] SDO " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") because phsRef is not Synchrophasor",
                             new Object[] { doType } ));
-                }
-            }
-            else {
-                diagnostics.add( new BasicDiagnostic(
-                        Diagnostic.WARNING,
-                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                        0,
-                        "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): DA phsRef not found",
-                        new Object[] { doType } ));
-            }
-            if( ! phsRefIsSynchrophasor ) {
-                for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) {
-                    if( presentSDO.get( name ) == null ) {
-                        diagnostics.add( new BasicDiagnostic(
-                                Diagnostic.ERROR,
-                                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
-                                0,
-                                "[NSD validation] SDO " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") because phsRef is not Synchrophasor",
-                                new Object[] { doType } ));
-                    }
+                    res = false;
                 }
             }
         }
-
         return res;
     }
 
+
 }
-- 
GitLab