Skip to main content

Profiles & Datatypes

CIM profile ontologies (RDFS schemas) describe which classes and properties exist in a model and what datatypes their values carry. CIMXML uses a profile registry to hold those ontologies so the parser can resolve a literal such as a Voltage to the right RDF datatype instead of leaving it as a plain string. This page covers the profile model, the registry API, and how datatype resolution is configured.

CimProfile​

A CimProfile (in de.soptim.opencgmes.cimxml.graph) wraps a profile ontology graph and exposes its metadata in a version-independent way. Profiles are versioned and identified by their version IRIs, which differ between CIM generations:

CIM versionVersion IRIsKeywordVersion info
CIM 16 (CGMES 2.4.15)cims:isFixed base/entsoe URIs{Profile}Version.shortName(none)
CIM 17/18 (CGMES 3.0+)owl:versionIRIdcat:keywordowl:versionInfo

Wrap a profile graph and query its metadata:

import de.soptim.opencgmes.cimxml.graph.CimProfile;

// Wrap a loaded profile graph
CimProfile profile = CimProfile.wrap(profileGraph);

String cimNamespace = profile.getCimNamespace();
Set<Node> versionIris = profile.getOwlVersionIris();
String keyword = profile.getDcatKeyword();
String versionInfo = profile.getOwlVersionInfo();
boolean isHeaderProfile = profile.isHeaderProfile();

A model profile describes the structure and properties of model data (Equipment, Topology, state variables, and so on); a header profile describes the structure of a model header (FullModel/DifferenceModel metadata). Header profiles are not referenced by the model itself, so the registry selects them by CIM namespace rather than by version IRI.

CimProfileRegistry​

CimProfileRegistry (in de.soptim.opencgmes.cimxml.rdfs) is the interface for managing profiles; CimProfileRegistryStd is the standard, caching implementation. Each CimXmlParser owns its own registry, accessible via getCimProfileRegistry().

import de.soptim.opencgmes.cimxml.rdfs.CimProfileRegistry;
import de.soptim.opencgmes.cimxml.rdfs.CimProfileRegistryStd;

// Create and configure a registry directly
CimProfileRegistry registry = new CimProfileRegistryStd();

// Register a profile
CimProfile profile = CimProfile.wrap(profileGraph);
registry.register(profile);

// Query registered profiles
Set<CimProfile> profiles = registry.getRegisteredProfiles();

When registering, the registry extracts the datatypes of every property in the profile and stores them in a map for fast lookup. Registration throws IllegalArgumentException if a profile's owlVersionIRI is already registered, or — for a header profile — if one is already registered for the same CIM version.

Registering profiles through the parser​

The most common path is to let the parser register profiles for you, so subsequent parses are profile-aware:

CimXmlParser parser = new CimXmlParser();
parser.parseAndRegisterCimProfile(Path.of("Equipment.rdf"));
parser.parseAndRegisterCimProfile(Path.of("Topology.rdf"));

CimDatasetGraph dataset = parser.parseCimModel(Path.of("model.xml"));

Datatype resolution​

Once profiles are registered, the parser resolves property datatypes from them. The registry returns a PropertyInfo record per property, capturing its domain class (rdfType), the property IRI, the CIM datatype, and either a primitiveType (an RDFDatatype, for datatype properties) or a referenceType (the range class, for object properties) — exactly one of the latter two is non-null.

import de.soptim.opencgmes.cimxml.rdfs.CimProfileRegistry.PropertyInfo;

// Look up properties + datatypes for a set of profile version IRIs
Map<Node, PropertyInfo> properties = registry.getPropertiesAndDatatypes(profileVersionIris);

// Header properties are looked up per CIM namespace
Map<Node, PropertyInfo> headerProps =
registry.getHeaderPropertiesAndDatatypes(cimNamespace);

The returned maps are thread-safe for reading.

Resolving properties with an rdfs:range instead of a CIM datatype​

Some properties carry no cims:dataType at all, only an rdfs:range. In that case the registry asks Jena's TypeMapper whether the range IRI is a registered RDFDatatype. If it is, the property is resolved as a datatype property using that type; if not, the range is treated as a reference type (the domain class of an object property) as before. This is what allows user-defined, non-XSD datatypes to work without a cims:dataType annotation, as long as the datatype IRI is registered with TypeMapper beforehand.

Registering custom primitive types​

If a profile uses a primitive type the library does not map out of the box, register a mapping from the CIM primitive type name to a Jena RDFDatatype. The datatype must also be registered with Jena's TypeMapper; registering the same name again overwrites the previous mapping.

import org.apache.jena.datatypes.xsd.XSDDatatype;

registry.registerPrimitiveType("Voltage", XSDDatatype.XSDdouble);
registry.registerPrimitiveType("Current", XSDDatatype.XSDdouble);

// Inspect the full primitive-type mapping
Map<String, RDFDatatype> mapping = registry.getPrimitiveToRdfDatatypeMapping();
Validate queries against these profiles

The same profile ontologies power CIMVocabCheck, which statically checks SPARQL and SHACL against the schema — unknown classes/properties, domain/range violations, and datatype mismatches — without running anything.