CIM RDF Schema Domain Models¶
Purpose and Overview¶
The GridLab.Gmss.Cim.Schemas namespace provides a strongly-typed .NET domain model that represents CIM RDF Schema files as defined by IEC 61970-552:2016. These schemas define the structure of CIM (Common Information Model) profiles used for power system model exchange.
A CIMXML model exchange document uses a subset of the CIM to address the model exchange needs of a specific use case; see Part 400 series profile documents. A CIM profile defines that portion of the CIM that an importer and exporter of a CIMXML document should be expected to handle. The RDF Schema for a profile then contains only the classes and properties defined for that profile.
A RDF Schema file can be generated from the CIM UML model by an application having a user interface where the subset of the CIM UML model is interactively specified. The RDF Schema file can be used by an application to validate a CIMXML document.

Key Objectives¶
This namespace serves multiple critical purposes in the GridLab GMSS RDF framework:
-
Type-Safe Schema Object Model: Provides C# classes that represent RDF Schema elements (classes, properties, enumerations), enabling compile-time type checking and IntelliSense support for developers working with CIM schemas.
-
Schema Parsing and Validation: Facilitates parsing of CIM RDF Schema XML files into in-memory object graphs for schema introspection and CIMXML document validation.
-
Multi-Version Support: Manages multiple schema profiles across different CGMES versions (2.4.15, 3.0.0), enabling cross-version compatibility and migration support.
-
Code Generation Support: Provides metadata extraction capabilities for generating C# classes, properties, and enumerations from CIM schema definitions.
-
Profile Management: Implements repository patterns for storing, querying, and organizing schema profiles by version and profile type.
Class Diagram¶
classDiagram
class IRdfXmlSchema {
<<interface>>
+string Version
+string Encoding
+string BaseUri
+RdfSchemaProfile Profile
+IReadOnlyDictionary~string,string~ Namespaces
}
class RdfXmlSchemaRoot {
<<abstract>>
+string Version
+string Encoding
+string BaseUri
+RdfSchemaProfile Profile
+IReadOnlyDictionary~string,string~ Namespaces
+int Count
+bool HasContent
+SetProfile(RdfSchemaProfile)
+AddNamespace(string prefix, string uri)
+FindNamespace(string prefix)
}
class RdfSchemaProfile {
+IRdfSchemaVersion Version
+IReadOnlyList~RdfSchemaPackage~ Packages
+IReadOnlyList~RdfSchemaClass~ Classes
+AddPackage(RdfSchemaPackage) RdfSchemaProfile
+AddPackages(IEnumerable~RdfSchemaPackage~) RdfSchemaProfile
+AddClass(RdfSchemaClass) RdfSchemaProfile
+AddClasses(IEnumerable~RdfSchemaClass~) RdfSchemaProfile
+GetClassByUri(string) RdfSchemaClass?
+GetClassByName(string) RdfSchemaClass?
+GetClassesByPackage(string) IEnumerable~RdfSchemaClass~
+GetEnumerations() IEnumerable~RdfSchemaClass~
+GetPrimitives() IEnumerable~RdfSchemaClass~
+GetCimDatatypes() IEnumerable~RdfSchemaClass~
+GetConcreteClasses() IEnumerable~RdfSchemaClass~
+GetAbstractClasses() IEnumerable~RdfSchemaClass~
+GetSubclasses(string) IEnumerable~RdfSchemaClass~
+GetInheritanceChain(string) IEnumerable~RdfSchemaClass~
+GetAllPropertiesForClass(string) IEnumerable~RdfSchemaProperty~
}
class RdfSchemaClass {
+string Uri
+string Name
+string Label
+string? Comment
+string? SuperClassUri
+string? PackageUri
+RdfSchemaStereotype Stereotype
+IReadOnlyList~string~ AdditionalStereotypes
+IReadOnlyList~RdfSchemaProperty~ Properties
+IReadOnlyList~RdfSchemaEnumValue~ EnumValues
+bool IsTopLevel
+bool IsEnumeration
+bool IsPrimitive
+bool IsCimDatatype
+bool IsConcrete
+bool IsAbstract
+WithComment(string) RdfSchemaClass
+WithSuperClass(string) RdfSchemaClass
+WithPackage(string) RdfSchemaClass
+WithStereotype(RdfSchemaStereotype) RdfSchemaClass
+AddStereotype(string) RdfSchemaClass
+AddProperty(RdfSchemaProperty) RdfSchemaClass
+AddProperties(IEnumerable~RdfSchemaProperty~) RdfSchemaClass
+AddEnumValue(RdfSchemaEnumValue) RdfSchemaClass
+AddEnumValues(IEnumerable~RdfSchemaEnumValue~) RdfSchemaClass
+GetAttributes()
+GetAssociations()
}
class RdfSchemaProperty {
+string Uri
+string Name
+string Label
+string? Comment
+string DomainUri
+string? RangeUri
+string? DataTypeUri
+string? InverseRoleNameUri
+string? FixedValue
+RdfSchemaMultiplicity Multiplicity
+RdfSchemaStereotype Stereotype
+bool IsAssociationUsed
+bool IsAttribute
+bool IsAssociation
+bool IsReadOnly
+bool IsNullable
+WithComment(string) RdfSchemaProperty
+WithDataType(string) RdfSchemaProperty
+WithRange(string) RdfSchemaProperty
+WithMultiplicity(RdfSchemaMultiplicity) RdfSchemaProperty
+WithStereotype(RdfSchemaStereotype) RdfSchemaProperty
+WithFixedValue(string) RdfSchemaProperty
+WithInverseRoleName(string) RdfSchemaProperty
+WithAssociationUsed(bool) RdfSchemaProperty
}
class RdfSchemaEnumValue {
+string Uri
+string Name
+string Label
+string? Comment
+string EnumerationUri
+WithComment(string) RdfSchemaEnumValue
}
class RdfSchemaPackage {
+string Uri
+string Label
+string? Comment
+WithComment(string) RdfSchemaPackage
}
class RdfSchemaVersion {
<<abstract>>
+string? Version
+string? BaseUml
+string? ShortName
+string? Description
+string? SourceName
+string ProfileIdentifier*
+WithVersion(string?) RdfSchemaVersion
+WithBaseUml(string?) RdfSchemaVersion
+WithShortName(string?) RdfSchemaVersion
+WithDescription(string?) RdfSchemaVersion
+WithSourceName(string?) RdfSchemaVersion
}
class RdfSchemaStereotype {
<<enumeration>>
None
Concrete
Enumeration
Primitive
CimDatatype
Attribute
Compound
EnumValue
European
Entsoe
ClassCategory
}
class RdfSchemaMultiplicity {
<<enumeration>>
Unspecified
ExactlyOne
ZeroOrOne
OneOrMore
ZeroOrMore
TwoOrMore
}
IRdfXmlSchema <|.. RdfXmlSchemaRoot
IRdfXmlSchema --> RdfSchemaProfile : Profile
RdfSchemaProfile --> RdfSchemaVersion
RdfSchemaProfile --> RdfSchemaClass : Classes
RdfSchemaProfile --> RdfSchemaPackage : Packages
RdfSchemaClass --> RdfSchemaProperty : Properties
RdfSchemaClass --> RdfSchemaEnumValue : EnumValues
RdfSchemaClass --> RdfSchemaStereotype
RdfSchemaProperty --> RdfSchemaMultiplicity
RdfSchemaProperty --> RdfSchemaStereotype Usage Examples¶
Working with Schema Classes¶
// Create a new schema class
var acLineSegment = new RdfSchemaClass(
uri: "#ACLineSegment",
name: "ACLineSegment",
label: "AC Line Segment")
.WithComment("A wire or combination of wires, with consistent electrical characteristics...")
.WithSuperClass("#Conductor")
.WithPackage("#Package_WiresProfile")
.WithStereotype(RdfSchemaStereotype.Concrete);
// Add properties to the class
var resistanceProperty = new RdfSchemaProperty(
uri: "#ACLineSegment.r",
name: "r",
label: "Resistance",
domainUri: "#ACLineSegment")
.WithComment("Positive sequence series resistance of the entire line section")
.WithDataType("#Resistance")
.WithMultiplicity(RdfSchemaMultiplicity.ExactlyOne)
.WithStereotype(RdfSchemaStereotype.Attribute);
acLineSegment.AddProperty(resistanceProperty);
// Check class characteristics
Console.WriteLine($"Is Concrete: {acLineSegment.IsConcrete}");
Console.WriteLine($"Is Top Level: {acLineSegment.IsTopLevel}");
Console.WriteLine($"Properties Count: {acLineSegment.Properties.Count}");
Working with Schema Properties¶
// Create an attribute property (has dataType)
var voltageProperty = new RdfSchemaProperty(
uri: "#Terminal.voltage",
name: "voltage",
label: "Voltage",
domainUri: "#Terminal")
.WithDataType("#Voltage")
.WithMultiplicity(RdfSchemaMultiplicity.ZeroOrOne)
.WithStereotype(RdfSchemaStereotype.Attribute);
Console.WriteLine($"Is Attribute: {voltageProperty.IsAttribute}");
Console.WriteLine($"Is Nullable: {voltageProperty.IsNullable}");
// Create an association property (has range to another class)
var terminalEquipmentProperty = new RdfSchemaProperty(
uri: "#Terminal.ConductingEquipment",
name: "ConductingEquipment",
label: "Conducting Equipment",
domainUri: "#Terminal")
.WithRange("#ConductingEquipment")
.WithMultiplicity(RdfSchemaMultiplicity.ExactlyOne)
.WithInverseRoleName("#ConductingEquipment.Terminals")
.WithAssociationUsed(true);
Console.WriteLine($"Is Association: {terminalEquipmentProperty.IsAssociation}");
Console.WriteLine($"Has Inverse: {!string.IsNullOrEmpty(terminalEquipmentProperty.InverseRoleNameUri)}");
// Create a fixed-value property (read-only)
var fixedMultiplierProperty = new RdfSchemaProperty(
uri: "#ActivePower.multiplier",
name: "multiplier",
label: "Multiplier",
domainUri: "#ActivePower")
.WithDataType("#UnitMultiplier")
.WithFixedValue("M")
.WithMultiplicity(RdfSchemaMultiplicity.ExactlyOne);
Console.WriteLine($"Is Read-Only: {fixedMultiplierProperty.IsReadOnly}");
Console.WriteLine($"Fixed Value: {fixedMultiplierProperty.FixedValue}");
Working with Enumerations¶
// Create an enumeration class
var phaseCode = new RdfSchemaClass(
uri: "#PhaseCode",
name: "PhaseCode",
label: "Phase Code")
.WithComment("Enumeration of phase identifiers")
.WithStereotype(RdfSchemaStereotype.Enumeration);
// Add enumeration values
var enumValues = new[]
{
new RdfSchemaEnumValue("#PhaseCode.A", "A", "Phase A", "#PhaseCode")
.WithComment("Phase A"),
new RdfSchemaEnumValue("#PhaseCode.B", "B", "Phase B", "#PhaseCode")
.WithComment("Phase B"),
new RdfSchemaEnumValue("#PhaseCode.C", "C", "Phase C", "#PhaseCode")
.WithComment("Phase C"),
new RdfSchemaEnumValue("#PhaseCode.ABC", "ABC", "Phases ABC", "#PhaseCode")
.WithComment("Three-phase")
};
foreach (var enumValue in enumValues)
{
phaseCode.AddEnumValue(enumValue);
}
Console.WriteLine($"Is Enumeration: {phaseCode.IsEnumeration}");
Console.WriteLine($"Enum Values: {phaseCode.EnumValues.Count}");
// Access enum values
foreach (var value in phaseCode.EnumValues)
{
Console.WriteLine($" {value.Name}: {value.Label}");
}
Querying Schema Profiles¶
// Assume we have a parsed profile
RdfSchemaProfile profile = /* ... */;
// Get all concrete classes
var concreteClasses = profile.GetConcreteClasses();
Console.WriteLine($"Concrete classes: {concreteClasses.Count()}");
// Get all enumerations
var enums = profile.GetEnumerations();
foreach (var enumClass in enums)
{
Console.WriteLine($"Enum: {enumClass.Name}");
foreach (var value in enumClass.EnumValues)
{
Console.WriteLine($" - {value.Name}");
}
}
// Get classes by package
var equipmentClasses = profile.GetClassesByPackage("#Package_CoreEquipmentProfile");
Console.WriteLine($"Equipment classes: {equipmentClasses.Count()}");
// Find a specific class
var terminal = profile.GetClassByName("Terminal");
if (terminal != null)
{
Console.WriteLine($"Found: {terminal.Label}");
Console.WriteLine($" Super Class: {terminal.SuperClassUri}");
Console.WriteLine($" Properties: {terminal.Properties.Count}");
}
// Get all datatypes
var datatypes = profile.GetCimDatatypes();
foreach (var datatype in datatypes)
{
Console.WriteLine($"Datatype: {datatype.Name}");
}
// Get all abstract classes
var abstractClasses = profile.GetAbstractClasses();
Console.WriteLine($"Abstract classes: {abstractClasses.Count()}");
Inheritance and Property Resolution¶
// Get the complete inheritance chain for a class
var inheritanceChain = profile.GetInheritanceChain("#ACLineSegment");
Console.WriteLine("Inheritance chain:");
foreach (var ancestor in inheritanceChain)
{
Console.WriteLine($" {ancestor.Name}");
}
// Get all properties including inherited ones
var allProperties = profile.GetAllPropertiesForClass("#ACLineSegment");
Console.WriteLine($"\nAll properties (including inherited): {allProperties.Count()}");
foreach (var property in allProperties)
{
var typeInfo = property.IsAttribute
? $"Attribute: {property.DataTypeUri}"
: $"Association: {property.RangeUri}";
Console.WriteLine($" {property.Name} ({typeInfo})");
}
// Get direct subclasses
var subclasses = profile.GetSubclasses("#Conductor");
Console.WriteLine($"\nDirect subclasses of Conductor:");
foreach (var subclass in subclasses)
{
Console.WriteLine($" {subclass.Name}");
}
// Check if a class is at the top of its hierarchy
var identifiedObject = profile.GetClassByName("IdentifiedObject");
if (identifiedObject != null)
{
Console.WriteLine($"\nIs top-level class: {identifiedObject.IsTopLevel}");
}
Working with Schema Packages¶
// Create packages
var corePackage = new RdfSchemaPackage(
uri: "#Package_Core",
label: "Core Package")
.WithComment("Core package contains fundamental types");
var equipmentPackage = new RdfSchemaPackage(
uri: "#Package_Equipment",
label: "Equipment Package")
.WithComment("Equipment package contains electrical equipment models");
// Build a profile
var version = new Cgmes3SchemaVersion()
.WithVersion("3.0.0")
.WithShortName("EQ")
.WithDescription("Equipment Profile");
var profile = new RdfSchemaProfile(version)
.AddPackage(corePackage)
.AddPackage(equipmentPackage);
// Add classes to the profile
profile.AddClass(identifiedObject)
.AddClass(acLineSegment)
.AddClass(terminal);
Console.WriteLine($"Profile: {profile.Version.ShortName}");
Console.WriteLine($"Classes: {profile.Classes.Count}");
Console.WriteLine($"Packages: {profile.Packages.Count}");
Supported Schema Versions¶
The domain models support both CGMES 2.4.15 and CGMES 3.0.0 schema formats:
- CGMES 2.4.15: Uses
http://iec.ch/TC57/2013/CIM-schema-cim16#namespace - CGMES 3.0.0: Uses
http://iec.ch/TC57/CIM100#namespace
Key RDF/RDFS Elements Parsed¶
| RDF Element | Domain Model | Description |
|---|---|---|
rdfs:Class | RdfSchemaClass | Represents a class definition |
rdf:Property | RdfSchemaProperty | Represents a property (attribute or association) |
rdfs:subClassOf | RdfSchemaClass.SuperClassUri | Defines class inheritance |
rdfs:label | Label property | Human-readable label |
rdfs:comment | Comment property | Optional description text |
rdfs:domain | RdfSchemaProperty.DomainUri | Class that defines the property |
rdfs:range | RdfSchemaProperty.RangeUri | Target class for associations |
cims:dataType | RdfSchemaProperty.DataTypeUri | Data type for attributes |
cims:multiplicity | RdfSchemaProperty.Multiplicity | Cardinality constraint (0..1, 1..1, 0.., 1..) |
cims:stereotype | Stereotype property | Classifies classes and properties |
cims:belongsToCategory | RdfSchemaClass.PackageUri | Package/category assignment |
cims:isFixed | RdfSchemaProperty.FixedValue | Constant/fixed value |
cims:inverseRoleName | RdfSchemaProperty.InverseRoleNameUri | Bidirectional association name |
cims:AssociationUsed | RdfSchemaProperty.IsAssociationUsed | Indicates which end to serialize |
Design Patterns¶
Value Objects¶
All schema domain classes inherit from ValueObject (ABP Framework), ensuring:
- Immutability: Properties are protected and can only be set through fluent methods
- Value Equality: Two instances are equal if their properties are equal
- Type Safety: Strong typing prevents accidental misuse
var class1 = new RdfSchemaClass("#Terminal", "Terminal", "Terminal");
var class2 = new RdfSchemaClass("#Terminal", "Terminal", "Terminal");
// Value equality - these are considered equal
Assert.True(class1.Equals(class2));
Fluent API Pattern¶
All domain classes use the With* prefix for fluent, chainable configuration:
var property = new RdfSchemaProperty("#Terminal.voltage", "voltage", "Voltage", "#Terminal")
.WithDataType("#Voltage")
.WithMultiplicity(RdfSchemaMultiplicity.ZeroOrOne)
.WithStereotype(RdfSchemaStereotype.Attribute)
.WithComment("The terminal voltage");
var schemaClass = new RdfSchemaClass("#ACLineSegment", "ACLineSegment", "AC Line Segment")
.WithSuperClass("#Conductor")
.WithPackage("#Package_Wires")
.WithStereotype(RdfSchemaStereotype.Concrete)
.AddProperty(property);
Computed Properties¶
Classes expose computed boolean properties for type checking:
// RdfSchemaClass
bool isEnum = schemaClass.IsEnumeration; // Stereotype == Enumeration
bool isPrimitive = schemaClass.IsPrimitive; // Stereotype == Primitive
bool isConcrete = schemaClass.IsConcrete; // Stereotype == Concrete || contains "concrete"
bool isAbstract = schemaClass.IsAbstract; // Not concrete, enum, primitive, or datatype
bool isTopLevel = schemaClass.IsTopLevel; // No super class defined
// RdfSchemaProperty
bool isAttribute = property.IsAttribute; // Has DataTypeUri
bool isAssociation = property.IsAssociation; // Has RangeUri
bool isReadOnly = property.IsReadOnly; // Has FixedValue
bool isNullable = property.IsNullable; // Multiplicity allows zero
Repository Pattern¶
The profile acts as a repository for schema elements with query methods:
// Query by type
var enums = profile.GetEnumerations();
var concreteClasses = profile.GetConcreteClasses();
var primitives = profile.GetPrimitives();
// Query by identifier
var terminal = profile.GetClassByUri("#Terminal");
var terminalByName = profile.GetClassByName("Terminal");
// Query by relationship
var subclasses = profile.GetSubclasses("#IdentifiedObject");
var classesInPackage = profile.GetClassesByPackage("#Package_Core");
// Inheritance queries
var chain = profile.GetInheritanceChain("#ACLineSegment");
var allProps = profile.GetAllPropertiesForClass("#ACLineSegment");
Type Safety with Enumerations¶
RdfSchemaStereotype and RdfSchemaMultiplicity enums provide type-safe classification:
// Stereotype classification
switch (schemaClass.Stereotype)
{
case RdfSchemaStereotype.Concrete:
// Can be instantiated
break;
case RdfSchemaStereotype.Enumeration:
// Has enum values
break;
case RdfSchemaStereotype.Primitive:
// Basic data type
break;
case RdfSchemaStereotype.CimDatatype:
// CIM-specific type with unit
break;
}
// Multiplicity-based logic
var isRequired = property.Multiplicity == RdfSchemaMultiplicity.ExactlyOne ||
property.Multiplicity == RdfSchemaMultiplicity.OneOrMore;
var isCollection = property.Multiplicity == RdfSchemaMultiplicity.ZeroOrMore ||
property.Multiplicity == RdfSchemaMultiplicity.OneOrMore;
See Also¶
- IEC 61970-501:2006 - Common Information Model (CIM) - Syntax for RDF
- CGMES Documentation - ENTSO-E Common Grid Model Exchange Standard
- RDF Schema Specification - W3C RDF Schema 1.1