diff --git a/README.rst b/README.rst index cdc8063d..6f8024c0 100644 --- a/README.rst +++ b/README.rst @@ -139,7 +139,7 @@ Call the generator with the appropriate target: usage: aas-core-codegen [-h] --model_path MODEL_PATH --snippets_dir SNIPPETS_DIR --output_dir OUTPUT_DIR --target - {csharp,cpp,golang,java,jsonschema,python,typescript,rdf_shacl,xsd,jsonld_context,protobuf,python_protobuf} + {csharp,cpp,golang,java,jsonschema,python,typescript,rdf_shacl,xsd,jsonld_context,protobuf,python_protobuf,opcua} [--version] Generate implementations and schemas based on an AAS meta-model. @@ -153,7 +153,7 @@ Call the generator with the appropriate target: specific code snippets --output_dir OUTPUT_DIR path to the generated code - --target {csharp,cpp,golang,java,jsonschema,python,typescript,rdf_shacl,xsd,jsonld_context,protobuf,python_protobuf} + --target {csharp,cpp,golang,java,jsonschema,python,typescript,rdf_shacl,xsd,jsonld_context,protobuf,python_protobuf,opcua} target language or schema --version show the current version and exit diff --git a/aas_core_codegen/intermediate/_translate.py b/aas_core_codegen/intermediate/_translate.py index 35115660..d9d31678 100644 --- a/aas_core_codegen/intermediate/_translate.py +++ b/aas_core_codegen/intermediate/_translate.py @@ -4437,6 +4437,54 @@ def _verify_only_simple_type_patterns(symbol_table: SymbolTable) -> List[Error]: return errors +def _verify_invariant_descriptions_unique(symbol_table: SymbolTable) -> List[Error]: + """Check that no two invariants share the same description.""" + errors = [] # type: List[Error] + for something_with_invariants in itertools.chain( + symbol_table.classes, symbol_table.constrained_primitives + ): + description_map = dict() # type: MutableMapping[str, Invariant] + + for invariant in something_with_invariants.invariants: + conflicting_invariant = description_map.get(invariant.description, None) + if conflicting_invariant is not None: + what: str + if isinstance(something_with_invariants, Class): + what = "class" + elif isinstance(something_with_invariants, ConstrainedPrimitive): + what = "constrained primitive" + else: + assert_never(something_with_invariants) + raise AssertionError("Unexpected execution path") + + if conflicting_invariant.specified_for is invariant.specified_for: + errors.append( + Error( + invariant.parsed.node, + f"The invariants' descriptions need to be unique, " + f"but they conflict " + f"in the {what} {invariant.specified_for.name!r} " + f"for the description: {invariant.description!r}", + ) + ) + else: + errors.append( + Error( + invariant.parsed.node, + f"The invariants' descriptions need to be unique, " + f"but an invariant from " + f"the {what} {invariant.specified_for.name!r} " + f"and from " + f"the {what} {conflicting_invariant.specified_for.name!r} " + f"conflict for the description: {invariant.description!r}", + ) + ) + else: + description_map[invariant.description] = invariant + + return errors + + def _verify_patterns_anchored_at_start_and_end( symbol_table: SymbolTable, ) -> List[Error]: @@ -4622,6 +4670,8 @@ def _verify(symbol_table: SymbolTable, ontology: _hierarchy.Ontology) -> List[Er errors.extend(_verify_patterns_anchored_at_start_and_end(symbol_table=symbol_table)) + errors.extend(_verify_invariant_descriptions_unique(symbol_table=symbol_table)) + if len(errors) > 0: return errors diff --git a/aas_core_codegen/main.py b/aas_core_codegen/main.py index b945592c..27ce4d4c 100644 --- a/aas_core_codegen/main.py +++ b/aas_core_codegen/main.py @@ -19,6 +19,7 @@ import aas_core_codegen.jsonld.main as jsonld_main import aas_core_codegen.protobuf.main as protobuf_main import aas_core_codegen.python_protobuf.main as python_protobuf_main +import aas_core_codegen.opcua.main as opcua_main from aas_core_codegen import run, specific_implementations from aas_core_codegen.common import LinenoColumner, assert_never @@ -40,6 +41,7 @@ class Target(enum.Enum): JSONLD_CONTEXT = "jsonld_context" PROTOBUF = "protobuf" PYTHON_PROTOBUF = "python_protobuf" + OPCUA = "opcua" class Parameters: @@ -174,6 +176,9 @@ def execute(params: Parameters, stdout: TextIO, stderr: TextIO) -> int: elif params.target is Target.PYTHON_PROTOBUF: return python_protobuf_main.execute(run_context, stdout=stdout, stderr=stderr) + elif params.target is Target.OPCUA: + return opcua_main.execute(run_context, stdout=stdout, stderr=stderr) + else: assert_never(params.target) diff --git a/aas_core_codegen/opcua/__init__.py b/aas_core_codegen/opcua/__init__.py new file mode 100644 index 00000000..ccc5301e --- /dev/null +++ b/aas_core_codegen/opcua/__init__.py @@ -0,0 +1 @@ +"""Generate the OPC UA Schema node set corresponding to the meta-model.""" diff --git a/aas_core_codegen/opcua/main.py b/aas_core_codegen/opcua/main.py new file mode 100644 index 00000000..e93527eb --- /dev/null +++ b/aas_core_codegen/opcua/main.py @@ -0,0 +1,1526 @@ +"""Generate the OPC UA Schema node set corresponding to the meta-model.""" +import collections +import dataclasses +import enum +import io +import itertools +import re +import xml.dom.minidom +import xml.etree.ElementTree as ET +import xml.sax.saxutils +from typing import ( + TextIO, + Tuple, + Optional, + List, + MutableMapping, + Mapping, + Union, + OrderedDict, + Iterable, + Set, +) + +from icontract import ensure, require + +import aas_core_codegen.opcua +import aas_core_codegen.opcua.naming as opcua_naming +from aas_core_codegen import ( + run, + intermediate, + specific_implementations, +) +from aas_core_codegen.common import ( + Error, + assert_never, + Identifier, + IDENTIFIER_RE, + Stripped, +) + +assert aas_core_codegen.opcua.__doc__ == __doc__ + +_PRIMITIVE_MAP = { + intermediate.PrimitiveType.BOOL: "Boolean", + intermediate.PrimitiveType.INT: "Int64", + intermediate.PrimitiveType.FLOAT: "Double", + intermediate.PrimitiveType.STR: "String", + intermediate.PrimitiveType.BYTEARRAY: "ByteString", +} +assert all(literal in _PRIMITIVE_MAP for literal in intermediate.PrimitiveType) + + +class _IdentifierMachine: + """ + Produce stable identifiers for different nodes. + + The Identifier Machine knows nothing about your scheme, so you have to come up + with your own. + + It will try to be as stable as possible, *i.e.*, the identifiers for the names + should not change even if the order of :py:func:`obtain` is changed. + + >>> machine = _IdentifierMachine() + >>> machine.obtain("something") + 207137056 + + Obtaining an identifier is idem-potent: + + >>> machine.obtain("something") + 207137056 + + Another text gives you another identifier: + + >>> machine.obtain("something_else") + 165180381 + """ + + def __init__(self) -> None: + self._identifier_map = dict() # type: MutableMapping[str, int] + self._taken_identifiers = set() # type: Set[int] + + @staticmethod + def _hash(text: str) -> int: + """ + Compute the non-cryptographic hash of the given string. + + We implement our own hash so that the implementation need not change across + different Python versions, in case they change the hash function. + + >>> _IdentifierMachine._hash("something") + 207137056 + + >>> _IdentifierMachine._hash("something_else") + 165180381 + + >>> _IdentifierMachine._hash("") + 7 + """ + result = 7 + for character in text: + result = (result * 31 + ord(character)) % 0x7FFFFFFF + + return result + + def obtain(self, text: str) -> int: + """ + Assign a slot for the text using hashing. + + In most cases, we do not expect the resulting ID to change. + """ + identifier = self._identifier_map.get(text, None) + if identifier is not None: + return identifier + + identifier = _IdentifierMachine._hash(text) + + while identifier in self._taken_identifiers: + identifier += 1 + + self._taken_identifiers.add(identifier) + self._identifier_map[text] = identifier + + return identifier + + +def _generate_aliases() -> ET.Element: + """Generate the aliases including the primitive values.""" + aliases = ET.Element("Aliases") + + for name, i in ( + ("Boolean", 1), + ("Int64", 8), + ("Double", 11), + ("String", 12), + ("ByteString", 15), + ("HasModellingRule", 37), + ("HasTypeDefinition", 40), + ("HasSubtype", 45), + ("HasProperty", 46), + ("HasComponent", 47), + ("HasInterface", 17603), + ): + alias = ET.Element("Alias", {"Alias": name}) + alias.text = f"i={i}" + aliases.append(alias) + + return aliases + + +@dataclasses.dataclass +class _IdentifiersForConstraints: + """Map the references and object types for constraints to identifiers.""" + + constraint_id: int + constraint_identifier_id: int + constraint_text_id: int + has_constraint_id: int + + +def _generate_for_constraints_and_patterns( + identifiers_for_constraints: _IdentifiersForConstraints, +) -> List[ET.Element]: + """Generate the object types and the references to represent constraints.""" + return [ + ET.fromstring( + f"""\ + + Constraint + + i=58 + ns=1;i={identifiers_for_constraints.constraint_identifier_id} + ns=1;i={identifiers_for_constraints.constraint_text_id} + +""" + ), + ET.fromstring( + f"""\ + + identifier + + i=68 + i=80 + +""" + ), + ET.fromstring( + f"""\ + + text + + i=68 + i=78 + +""" + ), + ET.fromstring( + f"""\ + + HasConstraint + + i=32 + + Constrains +""" + ), + ] + + +#: All the classes whose instances have an ``i=...`` in the node set. +_OpcUaIdentifiable = Union[ + intermediate.Enumeration, + intermediate.ConstrainedPrimitive, + intermediate.Class, + intermediate.Interface, + intermediate.Property, + intermediate.Invariant, +] + + +def _reference( + reference_type: str, target: str, is_forward: Optional[bool] = None +) -> ET.Element: + """Create a ```` element.""" + attrib = collections.OrderedDict([("ReferenceType", reference_type)]) + if is_forward is not None: + attrib["IsForward"] = "true" if is_forward else "false" + + reference_el = ET.Element("Reference", attrib) + reference_el.text = target + + return reference_el + + +def _localized_text(text: str) -> ET.Element: + """Create a nested ````.""" + localized_text_el = ET.Element("uax:LocalizedText") + + text_el = ET.Element("uax:Text") + localized_text_el.append(text_el) + + text_el.text = text + + return localized_text_el + + +def _generate_for_enum( + enumeration: intermediate.Enumeration, + identifier_map: Mapping[_OpcUaIdentifiable, int], + identifier_machine: _IdentifierMachine, + name_prefix: Identifier, +) -> List[ET.Element]: + """Define the enumeration as OPC UA EnumStrings.""" + enum_name = opcua_naming.enum_name(enumeration.name, name_prefix) + + result = [] # type: List[ET.Element] + + comment_starts = ET.Comment(f"{enum_name} starts.") + comment_starts.tail = "\n" + result.append(comment_starts) + + enum_id = identifier_map[enumeration] + + def generate_data_type() -> ET.Element: + """Generate the element defining the data type.""" + data_type_el = ET.Element( + "UADataType", + collections.OrderedDict( + [("NodeId", f"ns=1;i={enum_id}"), ("BrowseName", f"1:{enum_name}")] + ), + ) + + display_name_el = ET.Element("DisplayName") + data_type_el.append(display_name_el) + display_name_el.text = enum_name + + references_el = ET.Element("References") + data_type_el.append(references_el) + references_el.append( + _reference(reference_type="HasSubtype", target="i=29", is_forward=False) + ) + + definition_el = ET.Element("Definition", {"Name": f"1:{enum_name}"}) + data_type_el.append(definition_el) + + for i, literal in enumerate(enumeration.literals): + field = ET.Element( + "Field", + collections.OrderedDict( + [ + ("Name", opcua_naming.enum_literal_name(literal.name)), + ("Value", str(i)), + ] + ), + ) + definition_el.append(field) + + return data_type_el + + result.append(generate_data_type()) + + def generate_enum_strings() -> ET.Element: + """Generate the EnumString for the enumeration.""" + variable_id = identifier_machine.obtain(f"{enumeration.name}:variable") + + variable_el = ET.Element( + "UAVariable", + collections.OrderedDict( + [ + ("DataType", "LocalizedText"), + ("ValueRank", "1"), + ("NodeId", f"ns=1;i={variable_id}"), + ("ArrayDimensions", str(len(enumeration.literals))), + ("BrowseName", "EnumStrings"), + ("ParentNodeId", f"ns=1;i={enum_id}"), + ] + ), + ) + + display_name_el = ET.Element("DisplayName") + variable_el.append(display_name_el) + display_name_el.text = "EnumStrings" + + references_el = ET.Element("References") + variable_el.append(references_el) + references_el.append( + _reference("HasProperty", target=f"ns=1;i={enum_id}", is_forward=False) + ) + references_el.append(_reference("HasTypeDefinition", target="i=68")) + references_el.append(_reference("HasModellingRule", target="i=78")) + + value_el = ET.Element("Value") + variable_el.append(value_el) + + list_of_localized_text_el = ET.Element("uax:ListOfLocalizedText") + value_el.append(list_of_localized_text_el) + + for literal in enumeration.literals: + list_of_localized_text_el.append(_localized_text(literal.value)) + + return variable_el + + result.append(generate_enum_strings()) + + comment_ends = ET.Comment(f"{enum_name} ends.") + comment_ends.tail = "\n" + result.append(comment_ends) + + return result + + +_CONSTRAINT_ID_PREFIX_RE = re.compile(r"Constraint \s*(?P[^:]+)\s*:") + + +def _extract_constraint_identifier(description: str) -> Optional[str]: + """ + Try to extract the constraint identifier from the invariant description. + + >>> _extract_constraint_identifier("Constraint 1: bla bla bla") + '1' + + >>> _extract_constraint_identifier("Constraint 1 : bla bla bla") + '1' + + >>> _extract_constraint_identifier("Bla bla bla") + + >>> _extract_constraint_identifier("Constraint 2: Name with at most 9 characters.") + '2' + """ + match = _CONSTRAINT_ID_PREFIX_RE.match(description) + + if match is None: + return None + + return match.group("identifier").strip() + + +def _value_string(text: str) -> ET.Element: + """Generate an ```` element with the embedded string element.""" + value_el = ET.Element("Value") + + uax_string_el = ET.Element("uax:String") + value_el.append(uax_string_el) + uax_string_el.text = text + + return value_el + + +def _generate_for_invariant( + invariant: intermediate.Invariant, + identifier_map: Mapping[_OpcUaIdentifiable, int], + identifiers_for_constraints: _IdentifiersForConstraints, + identifier_machine: _IdentifierMachine, +) -> List[ET.Element]: + """Generate the constraint object for the invariant.""" + assert ( + invariant in identifier_map + ), f"Invariant {invariant.description!r} missing in identifier map" + + invariant_id = identifier_map[invariant] + + constraint_identifier = _extract_constraint_identifier(invariant.description) + + if constraint_identifier is None: + browse_name = f"ConstraintUnlabeled{invariant_id}" + else: + browse_name = opcua_naming.constraint_browser_name( + Stripped(constraint_identifier) + ) + + object_el = ET.fromstring( + f"""\ + + {browse_name} + + i=85 + ns=1;i={identifiers_for_constraints.constraint_id} + +""" + ) + + text_id = identifier_machine.obtain(f"{invariant_id}:text") + + text_variable_el = ET.fromstring( + f"""\ + + text + + ns=1;i={invariant_id} + i=63 + +""" + ) + + # NOTE (mristin): + # We have to create the ```` ourselves as we use a namespace alias and + # the ElementTree can not parse the namespace aliases from string. + text_variable_el.append(_value_string(invariant.description)) + + result = [object_el, text_variable_el] + + if constraint_identifier is not None: + identifier_id = identifier_machine.obtain(f"{invariant_id}:identifier") + identifier_variable_el = ET.fromstring( + f"""\ + + identifier + + ns=1;i={invariant_id} + i=63 + +""" + ) + + # NOTE (mristin): + # We have to create the ```` ourselves as we use a namespace alias and + # the ElementTree can not parse the namespace aliases from string. + identifier_variable_el.append(_value_string(constraint_identifier)) + + result.append(identifier_variable_el) + + return result + + +def _generate_for_constrained_primitive( + constrained_primitive: intermediate.ConstrainedPrimitive, + identifier_map: Mapping[_OpcUaIdentifiable, int], + identifiers_for_constraints: _IdentifiersForConstraints, + name_prefix: Identifier, +) -> ET.Element: + """Define the constrained primitive and link it with constraints.""" + constrained_primitive_name = opcua_naming.constrained_primitive_name( + constrained_primitive.name, prefix=name_prefix + ) + constrained_primitive_id = identifier_map[constrained_primitive] + + root = ET.fromstring( + f"""\ + + {constrained_primitive_name} + + {_PRIMITIVE_MAP[constrained_primitive.constrainee]} + +""" + ) + + references_el = root.find("References") + assert references_el is not None, "Expected in the node" + + for invariant in constrained_primitive.invariants: + # NOTE (mristin): + # We do not model inheritance between the constrained primitives as this + # is not possible in OPC UA. Hence, we define all the constraints for each + # constrained primitive. This causes a lot of repetition, but we found no other + # way around it. + + invariant_id = identifier_map[invariant] + + references_el.append( + ET.fromstring( + f"""\ +ns=1;i={invariant_id}""" + ) + ) + + return root + + +class _PropertyReferenceType(enum.Enum): + PROPERTY = 0 + COMPONENT = 1 + + +def _determine_property_reference_type( + prop: intermediate.Property, +) -> _PropertyReferenceType: + """ + Determine how to map the given property. + + In OPC UA, we distinguish between properties — attributes with simple data types or + arrays of simple data types — and components — references to instances + or aggregations of instances. + """ + type_anno = intermediate.beneath_optional(prop.type_annotation) + + if (intermediate.try_primitive_type(type_anno) is not None) or ( + isinstance(type_anno, intermediate.ListTypeAnnotation) + and intermediate.try_primitive_type(type_anno.items) is not None + ): + return _PropertyReferenceType.PROPERTY + + return _PropertyReferenceType.COMPONENT + + +def _try_primitive_type( + type_annotation: intermediate.TypeAnnotationUnion, +) -> Optional[intermediate.PrimitiveType]: + """ + Inspect the type annotation and determine the underlying primitive type, if any. + + The primitive type can either be in the annotation itself, beneath an optional + or beneath a list. + + This is different to :py:func:`intermediate.try_primitive_typ` since this function + considers lists as well. This is because OPC UA does not distinguish between + scalars and arrays when it comes to primitive types. + """ + type_anno = intermediate.beneath_optional(type_annotation) + + # NOTE (mristin): + # We make sure that we do not use the variable unintentionally. + del type_annotation + + if isinstance(type_anno, intermediate.PrimitiveTypeAnnotation): + return type_anno.a_type + + elif isinstance(type_anno, intermediate.OurTypeAnnotation) and isinstance( + type_anno.our_type, intermediate.ConstrainedPrimitive + ): + return type_anno.our_type.constrainee + + elif isinstance(type_anno, intermediate.ListTypeAnnotation) and isinstance( + type_anno.items, intermediate.PrimitiveTypeAnnotation + ): + return type_anno.items.a_type + + else: + return None + + +def _generate_references_for_properties( + properties: Iterable[intermediate.Property], + identifier_map: Mapping[_OpcUaIdentifiable, int], +) -> List[ET.Element]: + """ + Generate the ```` entries for the given properties. + + ``prop_to_id`` maps each property to an OPC UA identifier. + """ + result = [] # type: List[ET.Element] + + for prop in properties: + prop_id = identifier_map[prop] + + property_reference_type = _determine_property_reference_type(prop) + if property_reference_type is _PropertyReferenceType.PROPERTY: + result.append(_reference("HasProperty", f"ns=1;i={prop_id}")) + elif property_reference_type is _PropertyReferenceType.COMPONENT: + result.append(_reference("HasComponent", f"ns=1;i={prop_id}")) + else: + assert_never(property_reference_type) + + return result + + +@ensure(lambda result: result.tag in ("UAVariable", "UAObject")) +def _generate_for_property( + prop: intermediate.Property, + prop_id: int, + parent_id: int, + identifier_map: Mapping[_OpcUaIdentifiable, int], +) -> ET.Element: + """Generate the variable element corresponding to the property.""" + prop_name = opcua_naming.property_name(prop.name) + + root = ET.Element( + "", + attrib=collections.OrderedDict( + [ + ("NodeId", f"ns=1;i={prop_id}"), + ("BrowseName", f"1:{prop_name}"), + ("ParentNodeId", f"ns=1;i={parent_id}"), + ] + ), + ) + + display_name_el = ET.Element("DisplayName") + root.append(display_name_el) + display_name_el.text = prop_name + + if isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation): + type_anno = prop.type_annotation.value + else: + type_anno = prop.type_annotation + + if isinstance(type_anno, intermediate.OptionalTypeAnnotation): + raise AssertionError( + "NOTE (mristin): We do not handle optional optionals, but you " + f"specified type annotation {prop.type_annotation} for the property " + f"{prop.name!r}." + ) + + if isinstance(type_anno, intermediate.ListTypeAnnotation): + type_anno = type_anno.items + + elif isinstance( + type_anno, + (intermediate.PrimitiveTypeAnnotation, intermediate.OurTypeAnnotation), + ): + pass + + else: + assert_never(prop.type_annotation) + raise AssertionError("Unexpected execution path") + + if not isinstance( + type_anno, + (intermediate.PrimitiveTypeAnnotation, intermediate.OurTypeAnnotation), + ): + raise AssertionError( + f"NOTE (mristin): We only implemented optional and mandatory lists of " + f"primitives and lists of model instances, but you have " + f"a property {prop.name} with type: {prop.type_annotation}. " + f"Please contact the developers if you need this feature." + ) + + primitive_type = _try_primitive_type(type_anno) + + is_list = isinstance( + intermediate.beneath_optional(prop.type_annotation), + intermediate.ListTypeAnnotation, + ) + is_optional = isinstance(prop.type_annotation, intermediate.OptionalTypeAnnotation) + + references_el = ET.Element("References") + if primitive_type is not None: + if is_optional: + # NOTE (mristin): + # This corresponds to ``Optional``. + references_el.append(_reference("HasModellingRule", target="i=80")) + else: + # NOTE (mristin): + # This corresponds to ``Mandatory``. + references_el.append(_reference("HasModellingRule", target="i=78")) + else: + if is_list: + if is_optional: + # NOTE (mristin): + # This corresponds to ``OptionalPlaceholder``. + references_el.append(_reference("HasModellingRule", target="i=11508")) + else: + # NOTE (mristin): + # This corresponds to ``MandatoryPlaceholder``. + references_el.append(_reference("HasModellingRule", target="i=11510")) + else: + if is_optional: + # NOTE (mristin): + # This corresponds to ``Optional``. + references_el.append(_reference("HasModellingRule", target="i=80")) + else: + # NOTE (mristin): + # This corresponds to ``Mandatory``. + references_el.append(_reference("HasModellingRule", target="i=78")) + + if primitive_type is not None: + if isinstance(type_anno, intermediate.PrimitiveTypeAnnotation): + root.attrib["DataType"] = _PRIMITIVE_MAP[primitive_type] + + elif isinstance(type_anno, intermediate.OurTypeAnnotation) and isinstance( + type_anno.our_type, intermediate.ConstrainedPrimitive + ): + root.attrib["DataType"] = f"ns=1;i={identifier_map[type_anno.our_type]}" + + else: + raise AssertionError( + f"Unexpected primitive type in the property {prop.name!r} with " + f"type annotation {prop.type_annotation} where the type annotation " + f"beneath any Optional or List was: {type_anno}" + ) + + references_el.append(_reference("HasTypeDefinition", target="i=68")) + + if is_list: + root.attrib["ValueRank"] = "1" + + root.tag = "UAVariable" + else: + if isinstance(type_anno, intermediate.PrimitiveTypeAnnotation): + raise AssertionError( + "The case of the primitive type should have been handled before." + ) + elif isinstance(type_anno, intermediate.OurTypeAnnotation): + if isinstance(type_anno.our_type, intermediate.Enumeration): + root.tag = "UAVariable" + + enum_id = identifier_map[type_anno.our_type] + + root.attrib["DataType"] = f"ns=1;i={enum_id}" + + references_el.append(_reference("HasTypeDefinition", target="i=62")) + + elif isinstance(type_anno.our_type, intermediate.ConstrainedPrimitive): + raise AssertionError( + "The case of the primitive type should have been handled before." + ) + + elif isinstance( + type_anno.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ): + root.tag = "UAObject" + + if type_anno.our_type.interface is not None: + # NOTE (mristin): + # We specify the type as ``BaseObjectType`` since multiple + # inheritance is not possible. + references_el.append(_reference("HasTypeDefinition", target="i=58")) + + interface_id = identifier_map[type_anno.our_type.interface] + references_el.append( + _reference("HasInterface", target=f"ns=1;i={interface_id}") + ) + + for ancestor_cls in type_anno.our_type.ancestors: + assert ancestor_cls.interface is not None + + ancestor_id = identifier_map[ancestor_cls.interface] + references_el.append( + _reference("HasInterface", target=f"ns=1;i={ancestor_id}") + ) + + references_el.extend( + _generate_references_for_properties( + # NOTE (mristin): + # We reference *all* the properties of the object since + # the type definition is set to ``BaseObjectType``, but + # needs to satisfy all the interfaces. + properties=type_anno.our_type.properties, + identifier_map=identifier_map, + ) + ) + + else: + references_el.append( + _reference( + "HasTypeDefinition", + target=f"ns=1;i={identifier_map[type_anno.our_type]}", + ) + ) + else: + assert_never(type_anno.our_type) + else: + assert_never(type_anno) + + root.append(references_el) + + return root + + +def _generate_definitions_for_properties( + parent_id: int, + properties: Iterable[intermediate.Property], + identifier_map: Mapping[_OpcUaIdentifiable, int], +) -> List[ET.Element]: + """ + Generate the definition elements for all the properties. + + ``prop_to_id`` maps the properties to OPC UA identifiers. + """ + result = [] # type: List[ET.Element] + + for prop in properties: + prop_id = identifier_map[prop] + + property_el = _generate_for_property( + prop=prop, + prop_id=prop_id, + parent_id=parent_id, + identifier_map=identifier_map, + ) + + result.append(property_el) + + return result + + +def _generate_for_interface( + interface: intermediate.Interface, + identifier_map: Mapping[_OpcUaIdentifiable, int], + identifiers_for_constraints: _IdentifiersForConstraints, + name_prefix: Identifier, +) -> List[ET.Element]: + """Generate the definition for the given interface.""" + interface_name = opcua_naming.interface_name(interface.name, name_prefix) + + comment_starts = ET.Comment(f"{interface_name} starts.") + comment_starts.tail = "\n" + + result = [comment_starts] # type: List[ET.Element] + + interface_id = identifier_map[interface] + + object_type_el = ET.Element( + "UAObjectType", + collections.OrderedDict( + [ + ("NodeId", f"ns=1;i={interface_id}"), + ("BrowseName", f"1:{interface_name}"), + ("IsAbstract", "true"), + ] + ), + ) + result.append(object_type_el) + + display_name_el = ET.Element("DisplayName") + display_name_el.text = interface_name + object_type_el.append(display_name_el) + + strictly_interface_properties = [ + prop for prop in interface.properties if prop.specified_for is interface.base + ] + + references_el = ET.Element("References") + object_type_el.append(references_el) + + references_el.append(_reference("HasSubtype", target="i=17602", is_forward=False)) + + for invariant in interface.base.invariants: + if invariant.specified_for is not interface.base: + continue + + invariant_id = identifier_map[invariant] + + references_el.append( + _reference( + reference_type=f"ns=1;i={identifiers_for_constraints.has_constraint_id}", + target=f"ns=1;i={invariant_id}", + ) + ) + + references_el.extend( + _generate_references_for_properties( + properties=strictly_interface_properties, identifier_map=identifier_map + ) + ) + + result.extend( + _generate_definitions_for_properties( + parent_id=interface_id, + properties=strictly_interface_properties, + identifier_map=identifier_map, + ) + ) + + comment_ends = ET.Comment(f"{interface_name} ends.") + comment_ends.tail = "\n" + result.append(comment_ends) + + return result + + +def _generate_for_concrete_class( + cls: intermediate.ConcreteClass, + identifier_map: Mapping[_OpcUaIdentifiable, int], + identifiers_for_constraints: _IdentifiersForConstraints, + name_prefix: Identifier, +) -> List[ET.Element]: + """Generate the definition for the given concrete class.""" + cls_name = opcua_naming.class_name(cls.name, name_prefix) + cls_id = identifier_map[cls] + + result = [ET.Comment(f"{cls_name} starts.")] # type: List[ET.Element] + + object_type_el = ET.Element( + "UAObjectType", + attrib=collections.OrderedDict( + [("NodeId", f"ns=1;i={cls_id}"), ("BrowseName", f"1:{cls_name}")] + ), + ) + + display_name_el = ET.Element("DisplayName") + display_name_el.text = cls_name + object_type_el.append(display_name_el) + + references_el = ET.Element("References") + references_el.append(_reference("HasSubtype", target="i=58", is_forward=False)) + + if cls.interface is not None: + interface_id = identifier_map[cls.interface] + references_el.append(_reference("HasInterface", f"ns=1;i={interface_id}")) + + for ancestor_cls in cls.ancestors: + assert ancestor_cls.interface is not None + + assert ancestor_cls.interface in identifier_map, ( + f"The OPC UA identifier is missing for the interface corresponding to " + f"the ancestor class {ancestor_cls.name!r} of the class {cls.name!r}" + ) + + ancestor_id = identifier_map[ancestor_cls.interface] + references_el.append(_reference("HasInterface", f"ns=1;i={ancestor_id}")) + + if cls.interface is None: + # NOTE (mristin): + # We have to reference the constraints here since this concrete class has no + # interface, so no constraints have been referenced thus far. That is, we define + # the constraints in interfaces, but this class has none, so we have to + # reference them in the ``ObjectType`` corresponding to the class. + for invariant in cls.invariants: + if invariant.specified_for is not cls: + continue + + invariant_id = identifier_map[invariant] + + references_el.append( + _reference( + reference_type=f"ns=1;i={identifiers_for_constraints.has_constraint_id}", + target=f"ns=1;i={invariant_id}", + ) + ) + + else: + # NOTE (mristin): + # We assume that the object type needs to implement all the constraints imposed + # on its interfaces. Since we define an interface for any concrete class with + # descendants, we do not have to reference the constraints here. + pass + + strictly_cls_properties = [ + prop for prop in cls.properties if prop.specified_for is cls + ] + + references_el.extend( + _generate_references_for_properties( + properties=strictly_cls_properties, identifier_map=identifier_map + ) + ) + + object_type_el.append(references_el) + result.append(object_type_el) + + # NOTE (mristin): + # We define the properties only if they have not been already defined + # for an interface. + # Otherwise, we refer to the properties of the interfaces through + # ``HasComponent``/``HasProperty`` reference. + if cls.interface is None: + result.extend( + _generate_definitions_for_properties( + parent_id=cls_id, + properties=strictly_cls_properties, + identifier_map=identifier_map, + ) + ) + + result.append(ET.Comment(f"{cls_name} ends.")) + + return result + + +class _NamespaceDeclarations: + #: URL of the main namespace + main: str + + #: URL to namespace alias + url_to_alias: Mapping[str, str] + + #: Namespace alias to URL + alias_to_url: OrderedDict[str, str] + + # fmt: off + @require( + lambda url_to_alias, alias_to_url: + all( + alias_to_url[alias] == url + for url, alias in url_to_alias.items() + ) + ) + @require( + lambda url_to_alias, alias_to_url: + all( + url_to_alias[url] == alias + for alias, url in alias_to_url.items() + ) + ) + # fmt: on + def __init__( + self, + main: str, + url_to_alias: Mapping[str, str], + alias_to_url: OrderedDict[str, str], + ) -> None: + """Initialize with the given values.""" + self.main = main + self.url_to_alias = url_to_alias + self.alias_to_url = alias_to_url + + +def _extractNamespaceDeclarationsFromXML( + text: str, +) -> Tuple[Optional[_NamespaceDeclarations], Optional[str]]: + """ + Extract the namespace declarations from the given XML document. + + Return the parsed declarations, or error, if any. + """ + minidom_doc = xml.dom.minidom.parseString(text) + + main = None # type: Optional[str] + url_to_alias = dict() # type: MutableMapping[str, str] + alias_to_url = collections.OrderedDict() # type: OrderedDict[str, str] + + for attribute, value in minidom_doc.documentElement.attributes.items(): + if attribute == "xmlns": + main = value + elif attribute.startswith("xmlns:"): + alias = attribute[len("xmlns:") :] + url_to_alias[value] = alias + alias_to_url[alias] = value + else: + # NOTE (mristin): + # This attribute is otherwise irrelevant. + pass + + if main is None: + return None, "The main namespace is missing" + + return ( + _NamespaceDeclarations( + main=main, url_to_alias=url_to_alias, alias_to_url=alias_to_url + ), + None, + ) + + +INDENT = " " + +# NOTE (mristin): +# The ElementTree library is very peculiar when it comes to namespaces. The namespace +# URLs are directly inserted as prefixes to tag names, even when the user specifies +# an alias. +_ET_NAMESPACE_PREFIX_RE = re.compile(r"^\{(?P[^}]*)}") + + +def _render( + element: ET.Element, + writer: TextIO, + namespace_declarations: _NamespaceDeclarations, + level: int = 0, +) -> None: + """ + Render the given XML tree starting with the ``element`` at the root. + + We designed the rendering such that the XMLs are easy to read and diff. + """ + indention = INDENT * level + + if element.tag is ET.Comment: # type: ignore + writer.write(f"{indention}\n") + else: + if len(element) > 0: + if element.text is not None and not element.text.isspace(): + raise ValueError( + f"Unexpected element with children " + f"and non-whitespace text: {element}; " + f"the text was: {element.text!r}" + ) + + if element.tail is not None and not element.tail.isspace(): + raise ValueError( + f"Unexpected element with children " + f"and non-whitespace tail: {element}; " + f"the tail was: {element.tail!r}" + ) + + ns_match = _ET_NAMESPACE_PREFIX_RE.match(element.tag) + if ns_match is not None: + ns_url = ns_match.group("namespace") + + if ns_url == namespace_declarations.main: + # NOTE (mristin): + # We add 2 for the enclosing ``{`` and ``}``. + name = element.tag[len(ns_url) + 2 :] + else: + ns_alias = namespace_declarations.url_to_alias.get(ns_url, None) + if ns_alias is None: + raise ValueError( + f"Unexpected namespace URL in the ET element {element}. " + f"The declared namespaces aliases " + f"were: {namespace_declarations.url_to_alias}" + ) + + # NOTE (mristin): + # We add 2 for the enclosing ``{`` and ``}``. + local_name = element.tag[len(ns_url) + 2 :] + name = f"{ns_alias}:{local_name}" + else: + name = element.tag + + text = None # type: Optional[str] + if element.text is not None and not element.text.isspace(): + text = element.text + + if text is None and len(element) == 0: + if len(element.attrib) == 0: + writer.write(f"{indention}<{name} />\n") + else: + writer.write(f"{indention}<{name}\n") + for attrib, value in element.attrib.items(): + quoted_value = xml.sax.saxutils.quoteattr(value) + writer.write(f"{indention}{INDENT}{attrib}={quoted_value}\n") + + writer.write(f"{indention}/>\n") + + elif text is not None and len(element) == 0: + escaped_text = xml.sax.saxutils.escape(text) + + if len(element.attrib) == 0: + writer.write(f"{indention}<{name}>{escaped_text}\n") + else: + writer.write(f"{indention}<{name}\n") + + for attrib, value in element.attrib.items(): + quoted_value = xml.sax.saxutils.quoteattr(value) + writer.write(f"{indention}{INDENT}{attrib}={quoted_value}\n") + + writer.write(f"{indention}>{escaped_text}\n") + + elif text is None and len(element) > 0: + if len(element.attrib) == 0: + writer.write(f"{indention}<{name}>\n") + + for child in element: + _render( + element=child, + writer=writer, + namespace_declarations=namespace_declarations, + level=level + 1, + ) + + writer.write(f"{indention}\n") + else: + writer.write(f"{indention}<{name}\n") + + for attrib, value in element.attrib.items(): + quoted_value = xml.sax.saxutils.quoteattr(value) + writer.write(f"{indention}{INDENT}{attrib}={quoted_value}\n") + + writer.write(f"{indention}>\n") + + for child in element: + _render( + element=child, + writer=writer, + namespace_declarations=namespace_declarations, + level=level + 1, + ) + + writer.write(f"{indention}\n") + + else: + raise AssertionError("Unexpected execution path") + + +@ensure(lambda result: not (result[1] is not None) or (len(result[1]) >= 1)) +@ensure(lambda result: (result[0] is not None) ^ (result[1] is not None)) +@ensure(lambda result: not (result[0] is not None) or (result[0].endswith("\n"))) +def _generate( + symbol_table: intermediate.SymbolTable, + spec_impls: specific_implementations.SpecificImplementations, +) -> Tuple[Optional[str], Optional[List[Error]]]: + """Generate tne node set according to the symbol table.""" + base_nodeset_key = specific_implementations.ImplementationKey("base_nodeset.xml") + + base_nodeset_text = spec_impls.get(base_nodeset_key, None) + if base_nodeset_text is None: + return None, [ + Error( + None, + f"The implementation snippet for the base OPC UA nodeset " + f"is missing: {base_nodeset_key}", + ) + ] + + name_prefix_key = specific_implementations.ImplementationKey("name_prefix.txt") + + name_prefix_text = spec_impls.get(name_prefix_key, None) + if name_prefix_text is None: + return None, [ + Error( + None, + f"The implementation snippet for the type name prefix " + f"is missing: {name_prefix_key}", + ) + ] + + if not IDENTIFIER_RE.match(name_prefix_text): + return None, [ + Error( + None, + f"The implementation snippet for the type name prefix " + f"at {name_prefix_key} is invalid: {name_prefix_text}", + ) + ] + + name_prefix = Identifier(name_prefix_text) + + namespace_declarations, error = _extractNamespaceDeclarationsFromXML( + base_nodeset_text + ) + if error is not None: + return None, [ + Error( + None, + f"The namespaces could not be extracted from the implementation snippet " + f"for the base OPC UA nodeset {base_nodeset_key}: {error}", + ) + ] + + assert namespace_declarations is not None + + if "uax" not in namespace_declarations.alias_to_url: + return None, [ + Error( + None, + f"The namespace alias for 'uax' is missing in " + f"the implementation snippet for the base OPC UA " + f"nodeset: {base_nodeset_key}", + ) + ] + + try: + root = ET.fromstring(base_nodeset_text) + except Exception as err: + return None, [ + Error( + None, + f"Failed to parse the base nodeset XML out of " + f"the snippet {base_nodeset_key}: {err}", + ) + ] + + identifier_machine = _IdentifierMachine() + + identifier_map = ( + collections.OrderedDict() + ) # type: MutableMapping[_OpcUaIdentifiable, int] + + root.append(_generate_aliases()) + + # region Generate identifiers + + identifiers_for_constraints = _IdentifiersForConstraints( + # NOTE (mristin): + # We prefix here with ``_`` in order to avoid conflicts with AAS class names. + constraint_id=identifier_machine.obtain("_Constraint"), + constraint_identifier_id=identifier_machine.obtain("_Constraint.identifier"), + constraint_text_id=identifier_machine.obtain("_Constraint.text"), + has_constraint_id=identifier_machine.obtain("_HasConstraint"), + ) + + # noinspection SpellCheckingInspection + invariants = [ + invariant + for invariantable in itertools.chain( + symbol_table.classes, symbol_table.constrained_primitives + ) + for invariant in invariantable.invariants + if invariant.specified_for is invariantable + ] + + observed_invariant_uid_set = set() # type: Set[str] + + for invariant in invariants: + # NOTE (mristin): + # We rely on + # :py:func:`intermediate._translate._verify_invariant_descriptions_unique` + # that the invariant descriptions are unique. + + invariant_uid = ( + f"{invariant.specified_for.name}" f":invariant:{invariant.description}" + ) + + assert ( + invariant_uid not in observed_invariant_uid_set + ), f"Unexpected duplicate invariant ID for: {invariant_uid}" + observed_invariant_uid_set.add(invariant_uid) + + identifier_map[invariant] = identifier_machine.obtain(invariant_uid) + + for enumeration in symbol_table.enumerations: + identifier_map[enumeration] = identifier_machine.obtain(enumeration.name) + + for constrained_primitive in symbol_table.constrained_primitives: + identifier_map[constrained_primitive] = identifier_machine.obtain( + constrained_primitive.name + ) + + for cls in symbol_table.classes: + if cls.interface is not None: + identifier_map[cls.interface] = identifier_machine.obtain( + # NOTE (mristin): + # We prefix with ``interface:`` to avoid conflicts with + # concrete classes. + f"interface:{cls.name}" + ) + + for concrete_cls in symbol_table.concrete_classes: + identifier_map[concrete_cls] = identifier_machine.obtain(concrete_cls.name) + + for cls in symbol_table.classes: + for prop in cls.properties: + if prop.specified_for is not cls: + continue + + identifier_map[prop] = identifier_machine.obtain(f"{cls.name}.{prop.name}") + + # endregion + + root.extend( + _generate_for_constraints_and_patterns( + identifiers_for_constraints=identifiers_for_constraints + ) + ) + + if len(symbol_table.enumerations) > 0: + root.append(ET.Comment("Enumerations start here.")) + + for enumeration in symbol_table.enumerations: + root.extend( + _generate_for_enum( + enumeration=enumeration, + identifier_map=identifier_map, + identifier_machine=identifier_machine, + name_prefix=name_prefix, + ) + ) + + if len(symbol_table.enumerations) > 0: + root.append(ET.Comment("Enumerations end here.")) + + if len(invariants) > 0: + root.append(ET.Comment("Constraints start here.")) + + for invariant in invariants: + root.extend( + _generate_for_invariant( + invariant=invariant, + identifier_map=identifier_map, + identifiers_for_constraints=identifiers_for_constraints, + identifier_machine=identifier_machine, + ) + ) + + if len(invariants) > 0: + root.append(ET.Comment("Constraints end here.")) + + if len(symbol_table.constrained_primitives) > 0: + root.append(ET.Comment("Constrained primitives start here.")) + + for constrained_primitive in symbol_table.constrained_primitives: + root.append( + _generate_for_constrained_primitive( + constrained_primitive=constrained_primitive, + identifier_map=identifier_map, + identifiers_for_constraints=identifiers_for_constraints, + name_prefix=name_prefix, + ) + ) + + if len(symbol_table.constrained_primitives) > 0: + root.append(ET.Comment("Constrained primitives end here.")) + + for cls in symbol_table.classes: + if cls.interface is not None: + root.extend( + _generate_for_interface( + interface=cls.interface, + identifier_map=identifier_map, + identifiers_for_constraints=identifiers_for_constraints, + name_prefix=name_prefix, + ) + ) + + for concrete_cls in symbol_table.concrete_classes: + root.extend( + _generate_for_concrete_class( + cls=concrete_cls, + identifier_map=identifier_map, + identifiers_for_constraints=identifiers_for_constraints, + name_prefix=name_prefix, + ) + ) + + writer = io.StringIO() + + # NOTE (mristin): + # ElementTree removes the namespaces in the root, so we have to add them back + # manually. + root.attrib["xmlns"] = namespace_declarations.main + for alias, url in namespace_declarations.alias_to_url.items(): + root.attrib[f"xmlns:{alias}"] = url + + _render(element=root, writer=writer, namespace_declarations=namespace_declarations) + + return writer.getvalue(), None + + +def execute( + context: run.Context, + stdout: TextIO, + stderr: TextIO, +) -> int: + """ + Execute the generation with the given parameters. + + Return the error code, or 0 if no errors. + """ + code, errors = _generate( + symbol_table=context.symbol_table, spec_impls=context.spec_impls + ) + if errors is not None: + run.write_error_report( + message=f"Failed to generate the OPC UA node set " + f"based on {context.model_path}", + errors=[context.lineno_columner.error_message(error) for error in errors], + stderr=stderr, + ) + return 1 + + assert code is not None + + # noinspection SpellCheckingInspection + pth = context.output_dir / "nodeset.xml" + try: + pth.write_text(code, encoding="utf-8") + except Exception as exception: + run.write_error_report( + message=f"Failed to write the OPC UA node set to {pth}", + errors=[str(exception)], + stderr=stderr, + ) + return 1 + + stdout.write(f"Code generated to: {context.output_dir}\n") + + return 0 diff --git a/aas_core_codegen/opcua/naming.py b/aas_core_codegen/opcua/naming.py new file mode 100644 index 00000000..1f81a4de --- /dev/null +++ b/aas_core_codegen/opcua/naming.py @@ -0,0 +1,126 @@ +"""Generate the names for the OPC UA nodeset definitions.""" +import re + +from aas_core_codegen.common import Identifier, Stripped +from aas_core_codegen import naming + + +def enum_name(identifier: Identifier, prefix: Identifier) -> Identifier: + """ + Generate the name in OPC UA corresponding to the given enum identifier. + + >>> enum_name(Identifier("Something"), Identifier("AAS")) + 'AASSomethingDataType' + + >>> enum_name(Identifier("Something_better"), Identifier("AAS")) + 'AASSomethingBetterDataType' + + >>> enum_name(Identifier("Some_URL"), Identifier("AAS")) + 'AASSomeUrlDataType' + """ + return Identifier(prefix + naming.capitalized_camel_case(identifier) + "DataType") + + +def constrained_primitive_name( + identifier: Identifier, prefix: Identifier +) -> Identifier: + """ + Generate the name in OPC UA for the given constrained primitive identifier. + + >>> constrained_primitive_name(Identifier("Something"), Identifier("AAS")) + 'AASSomethingDataType' + + >>> constrained_primitive_name(Identifier("Something_better"), Identifier("AAS")) + 'AASSomethingBetterDataType' + + >>> constrained_primitive_name(Identifier("Some_URL"), Identifier("AAS")) + 'AASSomeUrlDataType' + """ + return Identifier(prefix + naming.capitalized_camel_case(identifier) + "DataType") + + +def class_name(identifier: Identifier, prefix: Identifier) -> Identifier: + """ + Generate the name in OPC UA corresponding to the given class identifier. + + >>> class_name(Identifier("Something"), Identifier("AAS")) + 'AASSomethingType' + + >>> class_name(Identifier("Something_better"), Identifier("AAS")) + 'AASSomethingBetterType' + + >>> class_name(Identifier("Some_URL"), Identifier("AAS")) + 'AASSomeUrlType' + """ + return Identifier(prefix + naming.capitalized_camel_case(identifier) + "Type") + + +def interface_name(identifier: Identifier, prefix: Identifier) -> Identifier: + """ + Generate the interface name in OPC UA corresponding to the given identifier. + + >>> interface_name(Identifier("Something"), Identifier("AAS")) + 'IAASSomethingType' + + >>> interface_name(Identifier("Something_better"), Identifier("AAS")) + 'IAASSomethingBetterType' + + >>> interface_name(Identifier("Some_URL"), Identifier("AAS")) + 'IAASSomeUrlType' + """ + return Identifier("I" + prefix + naming.capitalized_camel_case(identifier) + "Type") + + +def enum_literal_name(identifier: Identifier) -> Identifier: + """ + Generate the name of an enumeration literal. + + >>> enum_literal_name(Identifier("Something")) + 'Something' + + >>> enum_literal_name(Identifier("Something_better")) + 'SomethingBetter' + + >>> enum_literal_name(Identifier("Some_URL")) + 'SomeUrl' + """ + return naming.capitalized_camel_case(identifier) + + +def property_name(identifier: Identifier) -> Identifier: + """ + Generate the corresponding name for the property. + + >>> property_name(Identifier("Something")) + 'something' + + >>> property_name(Identifier("Something_better")) + 'somethingBetter' + + >>> property_name(Identifier("Some_URL")) + 'someUrl' + """ + return naming.lower_camel_case(identifier) + + +_NON_ALPHANUMERIC = re.compile(r"[^A-Za-z0-9]+") + + +def constraint_browser_name(invariant_identifier: Stripped) -> Identifier: + """ + Transform the invariant identifier into a valid browser name. + + >>> constraint_browser_name(Stripped('AASd-128')) + 'ConstraintAasd128' + + >>> constraint_browser_name(Stripped('AASc-3a-050')) + 'ConstraintAasc3a050' + + >>> constraint_browser_name(Stripped('1')) + 'Constraint1' + """ + parts = _NON_ALPHANUMERIC.split(invariant_identifier) + + parts_joined = "_".join(parts) + + return naming.capitalized_camel_case(Identifier(f"Constraint_{parts_joined}")) diff --git a/test_data/opcua/test_main/aas_core_meta.v3/expected_output/nodeset.xml b/test_data/opcua/test_main/aas_core_meta.v3/expected_output/nodeset.xml new file mode 100644 index 00000000..ba91dc57 --- /dev/null +++ b/test_data/opcua/test_main/aas_core_meta.v3/expected_output/nodeset.xml @@ -0,0 +1,10132 @@ + + + https://admin-shell.io/aas/3/0 + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + + AASModellingKindDataType + + i=29 + + + + + + + + EnumStrings + + ns=1;i=1285712171 + i=68 + i=78 + + + + + Template + + + Instance + + + + + + + + AASQualifierKindDataType + + i=29 + + + + + + + + + EnumStrings + + ns=1;i=1588134130 + i=68 + i=78 + + + + + ValueQualifier + + + ConceptQualifier + + + TemplateQualifier + + + + + + + + AASAssetKindDataType + + i=29 + + + + + + + + + EnumStrings + + ns=1;i=137744790 + i=68 + i=78 + + + + + Type + + + Instance + + + NotApplicable + + + + + + + + AASAasSubmodelElementsDataType + + i=29 + + + + + + + + + + + + + + + + + + + + + + + EnumStrings + + ns=1;i=2091663629 + i=68 + i=78 + + + + + AnnotatedRelationshipElement + + + BasicEventElement + + + Blob + + + Capability + + + DataElement + + + Entity + + + EventElement + + + File + + + MultiLanguageProperty + + + Operation + + + Property + + + Range + + + ReferenceElement + + + RelationshipElement + + + SubmodelElement + + + SubmodelElementList + + + SubmodelElementCollection + + + + + + + + AASEntityTypeDataType + + i=29 + + + + + + + + EnumStrings + + ns=1;i=1816233794 + i=68 + i=78 + + + + + CoManagedEntity + + + SelfManagedEntity + + + + + + + + AASDirectionDataType + + i=29 + + + + + + + + EnumStrings + + ns=1;i=1813380815 + i=68 + i=78 + + + + + input + + + output + + + + + + + + AASStateOfEventDataType + + i=29 + + + + + + + + EnumStrings + + ns=1;i=903895808 + i=68 + i=78 + + + + + on + + + off + + + + + + + + AASReferenceTypesDataType + + i=29 + + + + + + + + EnumStrings + + ns=1;i=1908390759 + i=68 + i=78 + + + + + ExternalReference + + + ModelReference + + + + + + + + AASKeyTypesDataType + + i=29 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EnumStrings + + ns=1;i=1131468949 + i=68 + i=78 + + + + + AnnotatedRelationshipElement + + + AssetAdministrationShell + + + BasicEventElement + + + Blob + + + Capability + + + ConceptDescription + + + DataElement + + + Entity + + + EventElement + + + File + + + FragmentReference + + + GlobalReference + + + Identifiable + + + MultiLanguageProperty + + + Operation + + + Property + + + Range + + + Referable + + + ReferenceElement + + + RelationshipElement + + + Submodel + + + SubmodelElement + + + SubmodelElementCollection + + + SubmodelElementList + + + + + + + + AASDataTypeDefXsdDataType + + i=29 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EnumStrings + + ns=1;i=809528606 + i=68 + i=78 + + + + + xs:anyURI + + + xs:base64Binary + + + xs:boolean + + + xs:byte + + + xs:date + + + xs:dateTime + + + xs:decimal + + + xs:double + + + xs:duration + + + xs:float + + + xs:gDay + + + xs:gMonth + + + xs:gMonthDay + + + xs:gYear + + + xs:gYearMonth + + + xs:hexBinary + + + xs:int + + + xs:integer + + + xs:long + + + xs:negativeInteger + + + xs:nonNegativeInteger + + + xs:nonPositiveInteger + + + xs:positiveInteger + + + xs:short + + + xs:string + + + xs:time + + + xs:unsignedByte + + + xs:unsignedInt + + + xs:unsignedLong + + + xs:unsignedShort + + + + + + + + AASDataTypeIec61360DataType + + i=29 + + + + + + + + + + + + + + + + + + + + + + + + + EnumStrings + + ns=1;i=1158888391 + i=68 + i=78 + + + + + DATE + + + STRING + + + STRING_TRANSLATABLE + + + INTEGER_MEASURE + + + INTEGER_COUNT + + + INTEGER_CURRENCY + + + REAL_MEASURE + + + REAL_COUNT + + + REAL_CURRENCY + + + BOOLEAN + + + IRI + + + IRDI + + + RATIONAL + + + RATIONAL_MEASURE + + + TIME + + + TIMESTAMP + + + FILE + + + HTML + + + BLOB + + + + + + + + + ConstraintUnlabeled555788616 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=555788616 + i=63 + + + Supplemental semantic IDs must be either not set or have at least one item. + + + + ConstraintAasd118 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=496009309 + i=63 + + + Constraint AASd-118: If there are supplemental semantic IDs defined then there shall be also a main semantic ID. + + + + identifier + + ns=1;i=496009309 + i=63 + + + AASd-118 + + + + ConstraintUnlabeled431800236 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=431800236 + i=63 + + + Refers-to must be either not set or have at least one item. + + + + ConstraintUnlabeled755644601 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=755644601 + i=63 + + + The value must match the value type. + + + + ConstraintUnlabeled1743103200 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1743103200 + i=63 + + + Extensions must be either not set or have at least one item. + + + + ConstraintAasd077 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1210200359 + i=63 + + + Constraint AASd-077: The name of an extension within Has-Extensions needs to be unique. + + + + identifier + + ns=1;i=1210200359 + i=63 + + + AASd-077 + + + + ConstraintUnlabeled1342222826 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1342222826 + i=63 + + + Description must be either not set or have at least one item. + + + + ConstraintUnlabeled108946094 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=108946094 + i=63 + + + Description must specify unique languages. + + + + ConstraintUnlabeled1837416454 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1837416454 + i=63 + + + Display name must be either not set or have at least one item. + + + + ConstraintUnlabeled1539763717 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1539763717 + i=63 + + + Display name must specify unique languages. + + + + ConstraintUnlabeled1764556352 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1764556352 + i=63 + + + Embedded data specifications must be either not set or have at least one item. + + + + ConstraintAasd005 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1775190642 + i=63 + + + Constraint AASd-005: If version is not specified then also revision shall be unspecified. This means, a revision requires a version. If there is no version there is no revision either. Revision is optional. + + + + identifier + + ns=1;i=1775190642 + i=63 + + + AASd-005 + + + + ConstraintUnlabeled1958245381 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1958245381 + i=63 + + + Qualifiers must be either not set or have at least one item. + + + + ConstraintAasd021 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=677490337 + i=63 + + + Constraint AASd-021: Every qualifiable can only have one qualifier with the same type. + + + + identifier + + ns=1;i=677490337 + i=63 + + + AASd-021 + + + + ConstraintAasd020 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=693255221 + i=63 + + + Constraint AASd-020: The value shall be consistent to the data type as defined in value type. + + + + identifier + + ns=1;i=693255221 + i=63 + + + AASd-020 + + + + ConstraintUnlabeled1732366660 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1732366660 + i=63 + + + Submodels must be either not set or have at least one item. + + + + ConstraintUnlabeled859407778 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=859407778 + i=63 + + + Derived-from must be a model reference to an asset administration shell. + + + + ConstraintUnlabeled1927712096 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1927712096 + i=63 + + + All submodels must be model references to a submodel. + + + + ConstraintAasd116 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=706890220 + i=63 + + + Constraint AASd-116: ``globalAssetId`` is a reserved key. If used as value for the name of specific asset ID then the value of specific asset ID shall be identical to the global asset ID. + + + + identifier + + ns=1;i=706890220 + i=63 + + + AASd-116 + + + + ConstraintAasd131 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=649413158 + i=63 + + + Constraint AASd-131: Either the global asset ID shall be defined or at least one specific asset ID. + + + + identifier + + ns=1;i=649413158 + i=63 + + + AASd-131 + + + + ConstraintUnlabeled1366058924 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1366058924 + i=63 + + + Specific asset IDs must be either not set or have at least one item. + + + + ConstraintAasd133 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1640567268 + i=63 + + + Constraint AASd-133: External subject ID shall be an external reference. + + + + identifier + + ns=1;i=1640567268 + i=63 + + + AASd-133 + + + + ConstraintUnlabeled1328468604 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1328468604 + i=63 + + + Submodel elements must be either not set or have at least one item. + + + + ConstraintUnlabeled1723854793 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1723854793 + i=63 + + + ID-shorts need to be defined for all the items of submodel elements according to AASd-117 (ID-short of Referables not being a direct child of a Submodel element list shall be specified). + + + + ConstraintAasd022 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=405415860 + i=63 + + + Constraint AASd-022: ID-short of non-identifiable referables within the same name space shall be unique (case-sensitive). + + + + identifier + + ns=1;i=405415860 + i=63 + + + AASd-022 + + + + ConstraintAasd129 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=42815708 + i=63 + + + Constraint AASd-129: If any qualifier kind value of a Submodel element qualifier (attribute qualifier inherited via Qualifiable) is equal to Template Qualifier then the submodel element shall be part of a submodel template, i.e. a Submodel with submodel kind (attribute kind inherited via Has-Kind) value is equal to Template. + + + + identifier + + ns=1;i=42815708 + i=63 + + + AASd-129 + + + + ConstraintAasd119 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=391322403 + i=63 + + + Constraint AASd-119: If any qualifier kind value of a qualifiable qualifier is equal to template qualifier and the qualified element has kind then the qualified element shall be of kind template. + + + + identifier + + ns=1;i=391322403 + i=63 + + + AASd-119 + + + + ConstraintUnlabeled1582412545 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1582412545 + i=63 + + + Value must be either not set or have at least one item. + + + + ConstraintAasd107 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=153292599 + i=63 + + + Constraint AASd-107: If a first level child element has a semantic ID it shall be identical to semantic ID list element. + + + + identifier + + ns=1;i=153292599 + i=63 + + + AASd-107 + + + + ConstraintAasd114 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=706168092 + i=63 + + + Constraint AASd-114: If two first level child elements have a semantic ID then they shall be identical. + + + + identifier + + ns=1;i=706168092 + i=63 + + + AASd-114 + + + + ConstraintAasd108 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=421845510 + i=63 + + + Constraint AASd-108: All first level child elements shall have the same submodel element type as specified in type value list element. + + + + identifier + + ns=1;i=421845510 + i=63 + + + AASd-108 + + + + ConstraintAasd109 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=952324917 + i=63 + + + Constraint AASd-109: If type value list element is equal to Property or Range value type list element shall be set and all first level child elements shall have the value type as specified in value type list element. + + + + identifier + + ns=1;i=952324917 + i=63 + + + AASd-109 + + + + ConstraintAasd120 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=381632945 + i=63 + + + Constraint AASd-120: ID-short of submodel elements being a direct child of a Submodel element list shall not be specified. + + + + identifier + + ns=1;i=381632945 + i=63 + + + AASd-120 + + + + ConstraintUnlabeled1127298839 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1127298839 + i=63 + + + Value must be either not set or have at least one item. + + + + ConstraintUnlabeled1474322569 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1474322569 + i=63 + + + ID-shorts need to be defined for all the items of value according to AASd-117 (ID-short of Referables not being a direct child of a Submodel element list shall be specified). + + + + ConstraintUnlabeled272135345 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=272135345 + i=63 + + + ID-shorts of the value must be unique. + + + + ConstraintAasd090 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=254410518 + i=63 + + + Constraint AASd-090: For data elements category shall be one of the following values: CONSTANT, PARAMETER or VARIABLE. + + + + identifier + + ns=1;i=254410518 + i=63 + + + AASd-090 + + + + ConstraintUnlabeled376501788 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=376501788 + i=63 + + + Value must be consistent with the value type. + + + + ConstraintUnlabeled1753391728 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1753391728 + i=63 + + + Value must specify unique languages. + + + + ConstraintUnlabeled1376297172 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1376297172 + i=63 + + + Value must be either not set or have at least one item. + + + + ConstraintUnlabeled222670808 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=222670808 + i=63 + + + Max must be consistent with the value type. + + + + ConstraintUnlabeled1771240833 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1771240833 + i=63 + + + Min must be consistent with the value type. + + + + ConstraintUnlabeled578421919 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=578421919 + i=63 + + + Annotations must be either not set or have at least one item. + + + + ConstraintUnlabeled2114614996 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=2114614996 + i=63 + + + ID-shorts need to be defined for all the items of annotations according to AASd-117 (ID-short of Referables not being a direct child of a Submodel element list shall be specified). + + + + ConstraintUnlabeled1322669586 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1322669586 + i=63 + + + Statements must be either not set or have at least one item. + + + + ConstraintUnlabeled816965897 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=816965897 + i=63 + + + ID-shorts need to be defined for all the items of statements according to AASd-117 (ID-short of Referables not being a direct child of a Submodel element list shall be specified). + + + + ConstraintAasd014 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=2000400456 + i=63 + + + Constraint AASd-014: Either the attribute global asset ID or specific asset ID must be set if entity type is set to self-managed entity. They are not existing otherwise. + + + + identifier + + ns=1;i=2000400456 + i=63 + + + AASd-014 + + + + ConstraintUnlabeled632673811 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=632673811 + i=63 + + + Specific asset IDs must be either not set or have at least one item. + + + + ConstraintUnlabeled305192771 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=305192771 + i=63 + + + Source must be a model reference to an Event element. + + + + ConstraintUnlabeled644017649 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=644017649 + i=63 + + + Observable reference must be a model reference to a referable. + + + + ConstraintUnlabeled1538525021 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1538525021 + i=63 + + + Max. interval is not applicable for input direction. + + + + ConstraintUnlabeled1671413178 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1671413178 + i=63 + + + Observed must be a model reference to a referable. + + + + ConstraintUnlabeled78380873 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=78380873 + i=63 + + + Message broker must be a model reference to a referable. + + + + ConstraintAasd134 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1146068082 + i=63 + + + Constraint AASd-134: For an Operation the ID-short of all values of input, output and in/output variables. + + + + identifier + + ns=1;i=1146068082 + i=63 + + + AASd-134 + + + + ConstraintUnlabeled168040306 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=168040306 + i=63 + + + Input variables must be either not set or have at least one item. + + + + ConstraintUnlabeled445675472 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=445675472 + i=63 + + + Output variables must be either not set or have at least one item. + + + + ConstraintUnlabeled1710131239 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1710131239 + i=63 + + + Inoutput variables must be either not set or have at least one item. + + + + ConstraintUnlabeled795400934 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=795400934 + i=63 + + + Value must have the ID-short specified according to Constraint AASd-117 (ID-short of Referables not being a direct child of a Submodel element list shall be specified). + + + + ConstraintUnlabeled332119539 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=332119539 + i=63 + + + Is-case-of must be either not set or have at least one item. + + + + ConstraintAasc3a008 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1457643744 + i=63 + + + Constraint AASc-3a-008: For a concept description using data specification template IEC 61360, the definition is mandatory and shall be defined at least in English. Exception: The concept description describes a value. + + + + identifier + + ns=1;i=1457643744 + i=63 + + + AASc-3a-008 + + + + ConstraintAasc3a007 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1633664109 + i=63 + + + Constraint AASc-3a-007: For a concept description with category QUALIFIER_TYPE using data specification IEC 61360, the data type of the data specification is mandatory and shall be defined. + + + + identifier + + ns=1;i=1633664109 + i=63 + + + AASc-3a-007 + + + + ConstraintAasc3a006 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=963584741 + i=63 + + + Constraint AASc-3a-006: For a concept description with category DOCUMENT using data specification IEC 61360, the data type of the data specification shall be one of: FILE, BLOB, HTML. + + + + identifier + + ns=1;i=963584741 + i=63 + + + AASc-3a-006 + + + + ConstraintAasc3a005 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=231674695 + i=63 + + + Constraint AASc-3a-005: For a concept description with category REFERENCE using data specification IEC 61360, the data type of the data specification shall be one of: STRING, IRI, IRDI. + + + + identifier + + ns=1;i=231674695 + i=63 + + + AASc-3a-005 + + + + ConstraintAasc3a004 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1252894240 + i=63 + + + Constraint AASc-3a-004: For a concept description with category PROPERTY or VALUE using data specification IEC 61360, the data type of the data specification is mandatory and shall be one of: DATE, STRING, STRING_TRANSLATABLE, INTEGER_MEASURE, INTEGER_COUNT, INTEGER_CURRENCY, REAL_MEASURE, REAL_COUNT, REAL_CURRENCY, BOOLEAN, RATIONAL, RATIONAL_MEASURE, TIME, TIMESTAMP. + + + + identifier + + ns=1;i=1252894240 + i=63 + + + AASc-3a-004 + + + + ConstraintUnlabeled1129265855 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1129265855 + i=63 + + + Keys must contain at least one item. + + + + ConstraintAasd121 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=845476204 + i=63 + + + Constraint AASd-121: For References the value of type of the first key of keys shall be one of Globally Identifiables. + + + + identifier + + ns=1;i=845476204 + i=63 + + + AASd-121 + + + + ConstraintAasd122 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=574697051 + i=63 + + + Constraint AASd-122: For external references the value of type of the first key of keys shall be one of Generic Globally Identifiables. + + + + identifier + + ns=1;i=574697051 + i=63 + + + AASd-122 + + + + ConstraintAasd123 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1241591198 + i=63 + + + Constraint AASd-123: For model references the value of type of the first key of keys shall be one of AAS identifiables. + + + + identifier + + ns=1;i=1241591198 + i=63 + + + AASd-123 + + + + ConstraintAasd124 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=635878123 + i=63 + + + Constraint AASd-124: For external references the last key of keys shall be either one of Generic Globally Identifiables or one of Generic Fragment Keys. + + + + identifier + + ns=1;i=635878123 + i=63 + + + AASd-124 + + + + ConstraintAasd125 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1845047759 + i=63 + + + Constraint AASd-125: For model references with more than one key in keys the value of type of each of the keys following the first key of keys shall be one of Fragment Keys. + + + + identifier + + ns=1;i=1845047759 + i=63 + + + AASd-125 + + + + ConstraintAasd126 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=385268813 + i=63 + + + Constraint AASd-126: For model references with more than one key in keys the value of type of the last key in the reference key chain may be one of Generic Fragment Keys or no key at all shall have a value out of Generic Fragment Keys. + + + + identifier + + ns=1;i=385268813 + i=63 + + + AASd-126 + + + + ConstraintAasd127 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=2093114950 + i=63 + + + Constraint AASd-127: For model references, with more than one key in keys a key with type Fragment Reference shall be preceded by a key with type File or Blob. + + + + identifier + + ns=1;i=2093114950 + i=63 + + + AASd-127 + + + + ConstraintAasd128 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=694939041 + i=63 + + + Constraint AASd-128: For model references, the value of a key preceded by a key with type Submodel element list is an integer number denoting the position in the array of the submodel element list. + + + + identifier + + ns=1;i=694939041 + i=63 + + + AASd-128 + + + + ConstraintUnlabeled1503433150 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1503433150 + i=63 + + + String shall have a maximum length of 128 characters. + + + + ConstraintUnlabeled2086522772 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=2086522772 + i=63 + + + String shall have a maximum length of 1023 characters. + + + + ConstraintUnlabeled1686087934 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1686087934 + i=63 + + + Concept descriptions must be either not set or have at least one item. + + + + ConstraintUnlabeled1112557295 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1112557295 + i=63 + + + Submodels must be either not set or have at least one item. + + + + ConstraintUnlabeled844502466 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=844502466 + i=63 + + + Asset administration shells must be either not set or have at least one item. + + + + ConstraintUnlabeled1930712396 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1930712396 + i=63 + + + Value reference pair types must contain at least one item. + + + + ConstraintUnlabeled132571440 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=132571440 + i=63 + + + String shall have a maximum length of 255 characters. + + + + ConstraintUnlabeled525217208 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=525217208 + i=63 + + + String shall have a maximum length of 18 characters. + + + + ConstraintUnlabeled1084675433 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1084675433 + i=63 + + + String shall have a maximum length of 1023 characters. + + + + ConstraintAasc3a010 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=2095462756 + i=63 + + + Constraint AASc-3a-010: If value is not empty then value list shall be empty and vice versa. + + + + identifier + + ns=1;i=2095462756 + i=63 + + + AASc-3a-010 + + + + ConstraintAasc3a009 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=531398414 + i=63 + + + Constraint AASc-3a-009: If data type is a an integer, real or rational with a measure or currency, unit or unit ID shall be defined. + + + + identifier + + ns=1;i=531398414 + i=63 + + + AASc-3a-009 + + + + ConstraintUnlabeled1531763943 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1531763943 + i=63 + + + Definition must be either not set or have at least one item. + + + + ConstraintUnlabeled759507522 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=759507522 + i=63 + + + Definition must specify unique languages. + + + + ConstraintUnlabeled467990461 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=467990461 + i=63 + + + Short name must be either not set or have at least one item. + + + + ConstraintUnlabeled1035529354 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1035529354 + i=63 + + + Short name must specify unique languages. + + + + ConstraintUnlabeled43753849 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=43753849 + i=63 + + + Preferred name must have at least one item. + + + + ConstraintUnlabeled839309022 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=839309022 + i=63 + + + Preferred name must specify unique languages. + + + + ConstraintAasc3a002 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=901554534 + i=63 + + + Constraint AASc-3a-002: preferred name shall be provided at least in English. + + + + identifier + + ns=1;i=901554534 + i=63 + + + AASc-3a-002 + + + + ConstraintAasd130 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1391739223 + i=63 + + + Constraint AASd-130: An attribute with data type 'string' shall consist of these characters only: ^[\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]*$. + + + + identifier + + ns=1;i=1391739223 + i=63 + + + AASd-130 + + + + ConstraintUnlabeled1586258210 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1586258210 + i=63 + + + The value must not be empty. + + + + ConstraintUnlabeled1046835270 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1046835270 + i=63 + + + The value must match the pattern of xs:dateTime with the time zone fixed to UTC. + + + + ConstraintUnlabeled1445582871 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1445582871 + i=63 + + + The value must represent a valid xs:dateTime with the time zone fixed to UTC. + + + + ConstraintUnlabeled1586553841 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1586553841 + i=63 + + + The value must match the pattern of xs:duration. + + + + ConstraintUnlabeled630288710 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=630288710 + i=63 + + + Identifier shall have a maximum length of 2000 characters. + + + + ConstraintUnlabeled554214960 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=554214960 + i=63 + + + Value type IEC 61360 shall have a maximum length of 2000 characters. + + + + ConstraintUnlabeled1564765132 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1564765132 + i=63 + + + Name type shall have a maximum length of 128 characters. + + + + ConstraintUnlabeled189016473 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=189016473 + i=63 + + + Version type shall match the version pattern. + + + + ConstraintUnlabeled1777922783 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1777922783 + i=63 + + + Version type shall have a maximum length of 4 characters. + + + + ConstraintUnlabeled1522784461 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1522784461 + i=63 + + + Revision type shall match the revision pattern. + + + + ConstraintUnlabeled1883511625 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1883511625 + i=63 + + + Revision type shall have a maximum length of 4 characters. + + + + ConstraintUnlabeled1729942909 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1729942909 + i=63 + + + Label type shall have a maximum length of 64 characters. + + + + ConstraintUnlabeled1086488324 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1086488324 + i=63 + + + Message topic type shall have a maximum length of 255 characters. + + + + ConstraintUnlabeled1886838026 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=1886838026 + i=63 + + + The value must represent a value language tag conformant to BCP 47. + + + + ConstraintUnlabeled19622443 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=19622443 + i=63 + + + Content type shall have a maximum length of 100 characters. + + + + ConstraintUnlabeled68549598 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=68549598 + i=63 + + + The value must represent a valid content MIME type according to RFC 2046. + + + + ConstraintUnlabeled58047943 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=58047943 + i=63 + + + ID-short of Referables shall only feature letters, digits, underscore (``_``); starting mandatory with a letter. *I.e.* ``[a-zA-Z][a-zA-Z0-9_]*``. + + + + + + AASNonEmptyXmlSerializableStringDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + + + + AASDateTimeUtcDataType + + String + ns=1;i=1046835270 + ns=1;i=1445582871 + + + + AASDurationDataType + + String + ns=1;i=1586553841 + + + + AASBlobTypeDataType + + ByteString + + + + AASIdentifierDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=630288710 + + + + AASValueTypeIec61360DataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=554214960 + + + + AASNameTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=1564765132 + + + + AASVersionTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=189016473 + ns=1;i=1777922783 + + + + AASRevisionTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=1522784461 + ns=1;i=1883511625 + + + + AASLabelTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=1729942909 + + + + AASMessageTopicTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=1086488324 + + + + AASBcp47LanguageTagDataType + + String + ns=1;i=1886838026 + + + + AASContentTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=19622443 + ns=1;i=68549598 + + + + AASPathTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=630288710 + + + + AASQualifierTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=1564765132 + + + + AASValueDataTypeDataType + + String + + + + AASIdShortTypeDataType + + String + ns=1;i=1391739223 + ns=1;i=1586258210 + ns=1;i=1564765132 + ns=1;i=58047943 + + + + + + IAASHasSemanticsType + + i=17602 + ns=1;i=555788616 + ns=1;i=496009309 + ns=1;i=280628610 + ns=1;i=511604664 + + + + semanticId + + i=80 + ns=1;i=1850821659 + + + + supplementalSemanticIds + + i=11508 + ns=1;i=1850821659 + + + + + + IAASHasExtensionsType + + i=17602 + ns=1;i=1743103200 + ns=1;i=1210200359 + ns=1;i=1897144208 + + + + extensions + + i=11508 + ns=1;i=15930846 + + + + + + IAASReferableType + + i=17602 + ns=1;i=1342222826 + ns=1;i=108946094 + ns=1;i=1837416454 + ns=1;i=1539763717 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + + + + category + + i=80 + i=68 + + + + idShort + + i=80 + i=68 + + + + displayName + + i=11508 + ns=1;i=1196143519 + + + + description + + i=11508 + ns=1;i=1072187332 + + + + + + IAASIdentifiableType + + i=17602 + ns=1;i=1544782491 + ns=1;i=1696112935 + + + + administration + + i=80 + ns=1;i=759920528 + + + + id + + i=78 + i=68 + + + + + + IAASHasKindType + + i=17602 + ns=1;i=666028309 + + + + kind + + i=80 + i=62 + + + + + + IAASHasDataSpecificationType + + i=17602 + ns=1;i=1764556352 + ns=1;i=1857412189 + + + + embeddedDataSpecifications + + i=11508 + ns=1;i=1702928339 + + + + + + IAASQualifiableType + + i=17602 + ns=1;i=1958245381 + ns=1;i=677490337 + ns=1;i=1395266523 + + + + qualifiers + + i=11508 + ns=1;i=1528036536 + + + + + + IAASSubmodelElementType + + i=17602 + + + + + + IAASRelationshipElementType + + i=17602 + ns=1;i=1430895529 + ns=1;i=1776122543 + + + + first + + i=78 + ns=1;i=1850821659 + + + + second + + i=78 + ns=1;i=1850821659 + + + + + + IAASDataElementType + + i=17602 + ns=1;i=254410518 + + + + + + IAASEventElementType + + i=17602 + + + + + + IAASAbstractLangStringType + + i=17602 + ns=1;i=1538665389 + ns=1;i=1263596220 + + + + language + + i=78 + i=68 + + + + text + + i=78 + i=68 + + + + + + IAASDataSpecificationContentType + + i=17602 + + + + + + AASExtensionType + + i=58 + ns=1;i=1469108797 + ns=1;i=431800236 + ns=1;i=755644601 + ns=1;i=1917113912 + ns=1;i=553458573 + ns=1;i=1455860607 + ns=1;i=1798131962 + + + + name + + i=78 + i=68 + + + + valueType + + i=80 + i=62 + + + + value + + i=80 + i=68 + + + + refersTo + + i=11508 + ns=1;i=1850821659 + + + + + + AASAdministrativeInformationType + + i=58 + ns=1;i=1908395787 + ns=1;i=1775190642 + ns=1;i=1828881379 + ns=1;i=437531159 + ns=1;i=358344496 + ns=1;i=521655076 + + + + version + + i=80 + i=68 + + + + revision + + i=80 + i=68 + + + + creator + + i=80 + ns=1;i=1850821659 + + + + templateId + + i=80 + i=68 + + + + + + AASQualifierType + + i=58 + ns=1;i=1469108797 + ns=1;i=693255221 + ns=1;i=1542881601 + ns=1;i=1543165159 + ns=1;i=1713444806 + ns=1;i=594608506 + ns=1;i=1536975416 + + + + kind + + i=80 + i=62 + + + + type + + i=78 + i=68 + + + + valueType + + i=78 + i=62 + + + + value + + i=80 + i=68 + + + + valueId + + i=80 + ns=1;i=1850821659 + + + + + + AASAssetAdministrationShellType + + i=58 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=2069020512 + ns=1;i=1908395787 + ns=1;i=1732366660 + ns=1;i=859407778 + ns=1;i=1927712096 + ns=1;i=1930228976 + ns=1;i=281957095 + ns=1;i=649162723 + + + + derivedFrom + + i=80 + ns=1;i=1850821659 + + + + assetInformation + + i=78 + ns=1;i=488983318 + + + + submodels + + i=11508 + ns=1;i=1850821659 + + + + + + AASAssetInformationType + + i=58 + ns=1;i=706890220 + ns=1;i=649413158 + ns=1;i=1366058924 + ns=1;i=1042222993 + ns=1;i=1106815944 + ns=1;i=67541404 + ns=1;i=1042506551 + ns=1;i=1635722420 + + + + assetKind + + i=78 + i=62 + + + + globalAssetId + + i=80 + i=68 + + + + specificAssetIds + + i=11508 + ns=1;i=687500411 + + + + assetType + + i=80 + i=68 + + + + defaultThumbnail + + i=80 + ns=1;i=2103787606 + + + + + + AASResourceType + + i=58 + ns=1;i=1728845782 + ns=1;i=59891365 + + + + path + + i=78 + i=68 + + + + contentType + + i=80 + i=68 + + + + + + AASSpecificAssetIdType + + i=58 + ns=1;i=1469108797 + ns=1;i=1640567268 + ns=1;i=64271993 + ns=1;i=1999819587 + ns=1;i=1279358926 + + + + name + + i=78 + i=68 + + + + value + + i=78 + i=68 + + + + externalSubjectId + + i=80 + ns=1;i=1850821659 + + + + + + AASSubmodelType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=2069020512 + ns=1;i=283983548 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=1328468604 + ns=1;i=1723854793 + ns=1;i=405415860 + ns=1;i=42815708 + ns=1;i=391322403 + ns=1;i=1170638648 + + + + submodelElements + + i=11508 + i=58 + ns=1;i=2063333151 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=1897144208 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + ns=1;i=280628610 + ns=1;i=511604664 + ns=1;i=1395266523 + ns=1;i=1857412189 + + + + + + AASRelationshipElementType + + i=58 + ns=1;i=1877389773 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1430895529 + ns=1;i=1776122543 + + + + + + AASSubmodelElementListType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1582412545 + ns=1;i=153292599 + ns=1;i=706168092 + ns=1;i=421845510 + ns=1;i=952324917 + ns=1;i=381632945 + ns=1;i=755462932 + ns=1;i=1666523306 + ns=1;i=493698289 + ns=1;i=52650848 + ns=1;i=1531868775 + + + + orderRelevant + + i=80 + i=68 + + + + semanticIdListElement + + i=80 + ns=1;i=1850821659 + + + + typeValueListElement + + i=78 + i=62 + + + + valueTypeListElement + + i=80 + i=62 + + + + value + + i=11508 + i=58 + ns=1;i=2063333151 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=1897144208 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + ns=1;i=280628610 + ns=1;i=511604664 + ns=1;i=1395266523 + ns=1;i=1857412189 + + + + + + AASSubmodelElementCollectionType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1127298839 + ns=1;i=1474322569 + ns=1;i=272135345 + ns=1;i=1617015401 + + + + value + + i=11508 + i=58 + ns=1;i=2063333151 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=1897144208 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + ns=1;i=280628610 + ns=1;i=511604664 + ns=1;i=1395266523 + ns=1;i=1857412189 + + + + + + AASPropertyType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=207853359 + ns=1;i=376501788 + ns=1;i=1026873260 + ns=1;i=1528958244 + ns=1;i=1066987760 + + + + valueType + + i=78 + i=62 + + + + value + + i=80 + i=68 + + + + valueId + + i=80 + ns=1;i=1850821659 + + + + + + AASMultiLanguagePropertyType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=207853359 + ns=1;i=1753391728 + ns=1;i=1376297172 + ns=1;i=2015253149 + ns=1;i=1353819953 + + + + value + + i=11508 + ns=1;i=1072187332 + + + + valueId + + i=80 + ns=1;i=1850821659 + + + + + + AASRangeType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=207853359 + ns=1;i=222670808 + ns=1;i=1771240833 + ns=1;i=884301582 + ns=1;i=2023222977 + ns=1;i=2023222739 + + + + valueType + + i=78 + i=62 + + + + min + + i=80 + i=68 + + + + max + + i=80 + i=68 + + + + + + AASReferenceElementType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=207853359 + ns=1;i=1101305618 + + + + value + + i=80 + ns=1;i=1850821659 + + + + + + AASBlobType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=207853359 + ns=1;i=976575225 + ns=1;i=1301359592 + + + + value + + i=80 + i=68 + + + + contentType + + i=78 + i=68 + + + + + + AASFileType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=207853359 + ns=1;i=899529003 + ns=1;i=1791501171 + + + + value + + i=80 + i=68 + + + + contentType + + i=78 + i=68 + + + + + + AASAnnotatedRelationshipElementType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1877389773 + ns=1;i=578421919 + ns=1;i=2114614996 + ns=1;i=131255443 + + + + annotations + + i=11508 + i=58 + ns=1;i=207853359 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1897144208 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + ns=1;i=280628610 + ns=1;i=511604664 + ns=1;i=1395266523 + ns=1;i=1857412189 + + + + + + AASEntityType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1322669586 + ns=1;i=816965897 + ns=1;i=2000400456 + ns=1;i=632673811 + ns=1;i=204103771 + ns=1;i=1386340701 + ns=1;i=364407196 + ns=1;i=2050093836 + + + + statements + + i=11508 + i=58 + ns=1;i=2063333151 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=1897144208 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + ns=1;i=280628610 + ns=1;i=511604664 + ns=1;i=1395266523 + ns=1;i=1857412189 + + + + entityType + + i=78 + i=62 + + + + globalAssetId + + i=80 + i=68 + + + + specificAssetIds + + i=11508 + ns=1;i=687500411 + + + + + + AASEventPayloadType + + i=58 + ns=1;i=305192771 + ns=1;i=644017649 + ns=1;i=2019977595 + ns=1;i=898421062 + ns=1;i=1242236952 + ns=1;i=1013418873 + ns=1;i=1520825988 + ns=1;i=1142068245 + ns=1;i=704193757 + ns=1;i=1577454665 + + + + source + + i=78 + ns=1;i=1850821659 + + + + sourceSemanticId + + i=80 + ns=1;i=1850821659 + + + + observableReference + + i=78 + ns=1;i=1850821659 + + + + observableSemanticId + + i=80 + ns=1;i=1850821659 + + + + topic + + i=80 + i=68 + + + + subjectId + + i=80 + ns=1;i=1850821659 + + + + timeStamp + + i=78 + i=68 + + + + payload + + i=80 + i=68 + + + + + + AASBasicEventElementType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=912227491 + ns=1;i=1538525021 + ns=1;i=1671413178 + ns=1;i=78380873 + ns=1;i=1645051436 + ns=1;i=572471291 + ns=1;i=891130204 + ns=1;i=685804772 + ns=1;i=1420013261 + ns=1;i=1965541827 + ns=1;i=333956984 + ns=1;i=2004084331 + + + + observed + + i=78 + ns=1;i=1850821659 + + + + direction + + i=78 + i=62 + + + + state + + i=78 + i=62 + + + + messageTopic + + i=80 + i=68 + + + + messageBroker + + i=80 + ns=1;i=1850821659 + + + + lastUpdate + + i=80 + i=68 + + + + minInterval + + i=80 + i=68 + + + + maxInterval + + i=80 + i=68 + + + + + + AASOperationType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + ns=1;i=1146068082 + ns=1;i=168040306 + ns=1;i=445675472 + ns=1;i=1710131239 + ns=1;i=473573299 + ns=1;i=1297398345 + ns=1;i=1418440206 + + + + inputVariables + + i=11508 + ns=1;i=657910559 + + + + outputVariables + + i=11508 + ns=1;i=657910559 + + + + inoutputVariables + + i=11508 + ns=1;i=657910559 + + + + + + AASOperationVariableType + + i=58 + ns=1;i=795400934 + ns=1;i=207367741 + + + + value + + i=78 + i=58 + ns=1;i=2063333151 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=1897144208 + ns=1;i=657707255 + ns=1;i=2033222391 + ns=1;i=508560987 + ns=1;i=1149204137 + ns=1;i=280628610 + ns=1;i=511604664 + ns=1;i=1395266523 + ns=1;i=1857412189 + + + + + + AASCapabilityType + + i=58 + ns=1;i=1469108797 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=1908395787 + ns=1;i=82107037 + ns=1;i=2063333151 + + + + + + AASConceptDescriptionType + + i=58 + ns=1;i=1783249887 + ns=1;i=1373018444 + ns=1;i=2069020512 + ns=1;i=1908395787 + ns=1;i=332119539 + ns=1;i=1457643744 + ns=1;i=1633664109 + ns=1;i=963584741 + ns=1;i=231674695 + ns=1;i=1252894240 + ns=1;i=346240304 + + + + isCaseOf + + i=11508 + ns=1;i=1850821659 + + + + + + AASReferenceType + + i=58 + ns=1;i=1129265855 + ns=1;i=845476204 + ns=1;i=574697051 + ns=1;i=1241591198 + ns=1;i=635878123 + ns=1;i=1845047759 + ns=1;i=385268813 + ns=1;i=2093114950 + ns=1;i=694939041 + ns=1;i=1055413450 + ns=1;i=851256044 + ns=1;i=1055126404 + + + + type + + i=78 + i=62 + + + + referredSemanticId + + i=80 + ns=1;i=1850821659 + + + + keys + + i=11510 + ns=1;i=283864 + + + + + + AASKeyType + + i=58 + ns=1;i=753256792 + ns=1;i=1877252893 + + + + type + + i=78 + i=62 + + + + value + + i=78 + i=68 + + + + + + AASLangStringNameTypeType + + i=58 + ns=1;i=1547392018 + ns=1;i=1503433150 + + + + + + AASLangStringTextTypeType + + i=58 + ns=1;i=1547392018 + ns=1;i=2086522772 + + + + + + AASEnvironmentType + + i=58 + ns=1;i=1686087934 + ns=1;i=1112557295 + ns=1;i=844502466 + ns=1;i=800122665 + ns=1;i=317702445 + ns=1;i=500368478 + + + + assetAdministrationShells + + i=11508 + ns=1;i=1879219494 + + + + submodels + + i=11508 + ns=1;i=378052933 + + + + conceptDescriptions + + i=11508 + ns=1;i=950292935 + + + + + + AASEmbeddedDataSpecificationType + + i=58 + ns=1;i=1860405716 + ns=1;i=296283050 + + + + dataSpecification + + i=78 + ns=1;i=1850821659 + + + + dataSpecificationContent + + i=78 + i=58 + ns=1;i=1660550080 + + + + + + AASLevelTypeType + + i=58 + ns=1;i=1965688644 + ns=1;i=1965689790 + ns=1;i=1965695869 + ns=1;i=1965688406 + + + + min + + i=78 + i=68 + + + + nom + + i=78 + i=68 + + + + typ + + i=78 + i=68 + + + + max + + i=78 + i=68 + + + + + + AASValueReferencePairType + + i=58 + ns=1;i=199306770 + ns=1;i=1903278388 + + + + value + + i=78 + i=68 + + + + valueId + + i=78 + ns=1;i=1850821659 + + + + + + AASValueListType + + i=58 + ns=1;i=1930712396 + ns=1;i=1017368757 + + + + valueReferencePairs + + i=11510 + ns=1;i=277739573 + + + + + + AASLangStringPreferredNameTypeIec61360Type + + i=58 + ns=1;i=1547392018 + ns=1;i=132571440 + + + + + + AASLangStringShortNameTypeIec61360Type + + i=58 + ns=1;i=1547392018 + ns=1;i=525217208 + + + + + + AASLangStringDefinitionTypeIec61360Type + + i=58 + ns=1;i=1547392018 + ns=1;i=1084675433 + + + + + + AASDataSpecificationIec61360Type + + i=58 + ns=1;i=1660550080 + ns=1;i=2095462756 + ns=1;i=531398414 + ns=1;i=1531763943 + ns=1;i=759507522 + ns=1;i=467990461 + ns=1;i=1035529354 + ns=1;i=43753849 + ns=1;i=839309022 + ns=1;i=901554534 + ns=1;i=1624314267 + ns=1;i=58107587 + ns=1;i=131592943 + ns=1;i=1127802764 + ns=1;i=1560884498 + ns=1;i=1859772541 + ns=1;i=1596935675 + ns=1;i=1772677410 + ns=1;i=1141942351 + ns=1;i=535438919 + ns=1;i=1932436839 + ns=1;i=846820463 + + + + preferredName + + i=11510 + ns=1;i=1692416216 + + + + shortName + + i=11508 + ns=1;i=618965522 + + + + unit + + i=80 + i=68 + + + + unitId + + i=80 + ns=1;i=1850821659 + + + + sourceOfDefinition + + i=80 + i=68 + + + + symbol + + i=80 + i=68 + + + + dataType + + i=80 + i=62 + + + + definition + + i=11508 + ns=1;i=118599192 + + + + valueFormat + + i=80 + i=68 + + + + valueList + + i=80 + ns=1;i=51601013 + + + + value + + i=80 + i=68 + + + + levelType + + i=80 + ns=1;i=362982557 + + + + diff --git a/test_data/opcua/test_main/aas_core_meta.v3/expected_output/stdout.txt b/test_data/opcua/test_main/aas_core_meta.v3/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/aas_core_meta.v3/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/aas_core_meta.v3/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/aas_core_meta.v3/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..39b9754e --- /dev/null +++ b/test_data/opcua/test_main/aas_core_meta.v3/input/snippets/base_nodeset.xml @@ -0,0 +1,20 @@ + + + + https://admin-shell.io/aas/3/0 + + + + + + + diff --git a/test_data/opcua/test_main/aas_core_meta.v3/input/snippets/name_prefix.txt b/test_data/opcua/test_main/aas_core_meta.v3/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/aas_core_meta.v3/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/abstract_and_concrete_classes/expected_output/nodeset.xml b/test_data/opcua/test_main/abstract_and_concrete_classes/expected_output/nodeset.xml new file mode 100644 index 00000000..210ed42f --- /dev/null +++ b/test_data/opcua/test_main/abstract_and_concrete_classes/expected_output/nodeset.xml @@ -0,0 +1,265 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + IAASSomethingAbstractType + + i=17602 + ns=1;i=608825403 + + + + someStr + + i=78 + i=68 + + + + + + AASSomethingConcreteType + + i=58 + ns=1;i=902726832 + ns=1;i=1159452538 + + + + somethingStr + + i=78 + i=68 + + + + + + AASAnotherConcreteType + + i=58 + ns=1;i=902726832 + ns=1;i=692798364 + + + + anotherStr + + i=78 + i=68 + + + + + + AASContainerType + + i=58 + ns=1;i=198270989 + + + + somethingAbstract + + i=78 + i=58 + ns=1;i=902726832 + ns=1;i=608825403 + + + + diff --git a/test_data/opcua/test_main/abstract_and_concrete_classes/expected_output/stdout.txt b/test_data/opcua/test_main/abstract_and_concrete_classes/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/abstract_and_concrete_classes/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/abstract_and_concrete_classes/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/abstract_and_concrete_classes/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/abstract_and_concrete_classes/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/abstract_and_concrete_classes/input/snippets/name_prefix.txt b/test_data/opcua/test_main/abstract_and_concrete_classes/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/abstract_and_concrete_classes/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/abstract_and_concrete_classes/meta_model.py b/test_data/opcua/test_main/abstract_and_concrete_classes/meta_model.py new file mode 100644 index 00000000..2bec28db --- /dev/null +++ b/test_data/opcua/test_main/abstract_and_concrete_classes/meta_model.py @@ -0,0 +1,37 @@ +@abstract +@serialization(with_model_type=True) +class Something_abstract: + some_str: str + + def __init__(self, some_str: str) -> None: + self.some_str = some_str + + +class Something_concrete(Something_abstract): + something_str: str + + def __init__(self, some_str: str, something_str: str) -> None: + Something_abstract.__init__(self, some_str) + + self.something_str = something_str + + +class Another_concrete(Something_abstract): + another_str: str + + def __init__(self, some_str: str, another_str: str) -> None: + Something_abstract.__init__(self, some_str) + + self.another_str = another_str + + +class Container: + something_abstract: Something_abstract + + def __init__(self, something_abstract: Something_abstract) -> None: + self.something_abstract = something_abstract + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/classes_with_invariants/expected_output/nodeset.xml b/test_data/opcua/test_main/classes_with_invariants/expected_output/nodeset.xml new file mode 100644 index 00000000..2ab6ad69 --- /dev/null +++ b/test_data/opcua/test_main/classes_with_invariants/expected_output/nodeset.xml @@ -0,0 +1,312 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + Constraint1 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=522741222 + i=63 + + + Constraint 1: Name with at least 3 characters + + + + identifier + + ns=1;i=522741222 + i=63 + + + 1 + + + + Constraint2 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=43936234 + i=63 + + + Constraint 2: Name with at most 9 characters. + + + + identifier + + ns=1;i=43936234 + i=63 + + + 2 + + + + + + IAASSomethingConcreteType + + i=17602 + ns=1;i=522741222 + ns=1;i=382843664 + + + + name + + i=78 + i=68 + + + + + + AASSomethingConcreteType + + i=58 + ns=1;i=734668594 + ns=1;i=382843664 + + + + + + AASSomethingMoreConcreteType + + i=58 + ns=1;i=734668594 + ns=1;i=43936234 + + + + diff --git a/test_data/opcua/test_main/classes_with_invariants/expected_output/stdout.txt b/test_data/opcua/test_main/classes_with_invariants/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/classes_with_invariants/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/classes_with_invariants/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/classes_with_invariants/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/classes_with_invariants/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/classes_with_invariants/input/snippets/name_prefix.txt b/test_data/opcua/test_main/classes_with_invariants/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/classes_with_invariants/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/classes_with_invariants/meta_model.py b/test_data/opcua/test_main/classes_with_invariants/meta_model.py new file mode 100644 index 00000000..5cb3fb55 --- /dev/null +++ b/test_data/opcua/test_main/classes_with_invariants/meta_model.py @@ -0,0 +1,21 @@ +@invariant( + lambda self: len(self.name) > 2, "Constraint 1: Name with at least 3 characters" +) +class Something_concrete: + name: str + + def __init__(self, name: str) -> None: + self.name = name + + +@invariant( + lambda self: len(self.name) < 10, "Constraint 2: Name with at most 9 characters." +) +class Something_more_concrete(Something_concrete): + def __init__(self, name: str) -> None: + Something_concrete.__init__(self, name) + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/concrete_class_with_descendant/expected_output/nodeset.xml b/test_data/opcua/test_main/concrete_class_with_descendant/expected_output/nodeset.xml new file mode 100644 index 00000000..04945a44 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_descendant/expected_output/nodeset.xml @@ -0,0 +1,249 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + IAASSomethingType + + i=17602 + ns=1;i=475297679 + + + + someStr + + i=78 + i=68 + + + + + + AASSomethingType + + i=58 + ns=1;i=1733419516 + ns=1;i=475297679 + + + + + + AASSomethingMoreConcreteType + + i=58 + ns=1;i=1733419516 + ns=1;i=846084331 + + + + someMoreConcreteStr + + i=78 + i=68 + + + + + + AASContainerType + + i=58 + ns=1;i=993564115 + + + + something + + i=78 + i=58 + ns=1;i=1733419516 + ns=1;i=475297679 + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_descendant/expected_output/stdout.txt b/test_data/opcua/test_main/concrete_class_with_descendant/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_descendant/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/concrete_class_with_descendant/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/concrete_class_with_descendant/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_descendant/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_descendant/input/snippets/name_prefix.txt b/test_data/opcua/test_main/concrete_class_with_descendant/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_descendant/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/concrete_class_with_descendant/meta_model.py b/test_data/opcua/test_main/concrete_class_with_descendant/meta_model.py new file mode 100644 index 00000000..c2da45e7 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_descendant/meta_model.py @@ -0,0 +1,27 @@ +@serialization(with_model_type=True) +class Something: + some_str: str + + def __init__(self, some_str: str) -> None: + self.some_str = some_str + + +class Something_more_concrete(Something): + some_more_concrete_str: str + + def __init__(self, some_str: str, some_more_concrete_str: str) -> None: + Something.__init__(self, some_str) + + self.some_more_concrete_str = some_more_concrete_str + + +class Container: + something: Something + + def __init__(self, something: Something) -> None: + self.something = something + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/concrete_class_with_enum/expected_output/nodeset.xml b/test_data/opcua/test_main/concrete_class_with_enum/expected_output/nodeset.xml new file mode 100644 index 00000000..b924b4de --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_enum/expected_output/nodeset.xml @@ -0,0 +1,233 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + + AASModellingKindDataType + + i=29 + + + + + + + + EnumStrings + + ns=1;i=1285712171 + i=68 + i=78 + + + + + Template + + + Instance + + + + + + + + + AASSomethingType + + i=58 + ns=1;i=1993798949 + ns=1;i=629865262 + + + + modellingKind + + i=78 + i=62 + + + + optionalModellingKind + + i=80 + i=62 + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_enum/expected_output/stdout.txt b/test_data/opcua/test_main/concrete_class_with_enum/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_enum/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/concrete_class_with_enum/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/concrete_class_with_enum/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_enum/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_enum/input/snippets/name_prefix.txt b/test_data/opcua/test_main/concrete_class_with_enum/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_enum/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/concrete_class_with_enum/meta_model.py b/test_data/opcua/test_main/concrete_class_with_enum/meta_model.py new file mode 100644 index 00000000..196aebbc --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_enum/meta_model.py @@ -0,0 +1,21 @@ +class Modelling_kind(Enum): + Template = "Template" + Instance = "Instance" + + +class Something: + modelling_kind: Modelling_kind + optional_modelling_kind: Optional[Modelling_kind] + + def __init__( + self, + modelling_kind: Modelling_kind, + optional_modelling_kind: Optional[Modelling_kind], + ) -> None: + self.modelling_kind = modelling_kind + self.optional_modelling_kind = optional_modelling_kind + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/concrete_class_with_list_of_instances/expected_output/nodeset.xml b/test_data/opcua/test_main/concrete_class_with_list_of_instances/expected_output/nodeset.xml new file mode 100644 index 00000000..27a8f323 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_list_of_instances/expected_output/nodeset.xml @@ -0,0 +1,204 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + AASItemType + + i=58 + ns=1;i=77333973 + + + + someStr + + i=78 + i=68 + + + + + + AASSomethingType + + i=58 + ns=1;i=1965185715 + ns=1;i=871075555 + + + + items + + i=11510 + ns=1;i=8754106 + + + + optionalItems + + i=11508 + ns=1;i=8754106 + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_list_of_instances/expected_output/stdout.txt b/test_data/opcua/test_main/concrete_class_with_list_of_instances/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_list_of_instances/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/concrete_class_with_list_of_instances/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/concrete_class_with_list_of_instances/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_list_of_instances/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_list_of_instances/input/snippets/name_prefix.txt b/test_data/opcua/test_main/concrete_class_with_list_of_instances/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_list_of_instances/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/concrete_class_with_list_of_instances/meta_model.py b/test_data/opcua/test_main/concrete_class_with_list_of_instances/meta_model.py new file mode 100644 index 00000000..747452d9 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_list_of_instances/meta_model.py @@ -0,0 +1,19 @@ +class Item: + some_str: str + + def __init__(self, some_str: str) -> None: + self.some_str = some_str + + +class Something: + items: List[Item] + optional_items: Optional[List[Item]] + + def __init__(self, items: List[Item], optional_items: Optional[List[Item]]) -> None: + self.items = items + self.optional_items = optional_items + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/concrete_class_with_primitive_attributes/expected_output/nodeset.xml b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/expected_output/nodeset.xml new file mode 100644 index 00000000..ab604e38 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/expected_output/nodeset.xml @@ -0,0 +1,325 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + AASSomethingType + + i=58 + ns=1;i=1848814930 + ns=1;i=475287885 + ns=1;i=1482292494 + ns=1;i=475297679 + ns=1;i=1031155976 + ns=1;i=411659599 + ns=1;i=1260212028 + ns=1;i=2027633820 + ns=1;i=1260221822 + ns=1;i=967010685 + + + + someBool + + i=78 + i=68 + + + + someInt + + i=78 + i=68 + + + + someFloat + + i=78 + i=68 + + + + someStr + + i=78 + i=68 + + + + someByteArray + + i=78 + i=68 + + + + someOptionalBool + + i=80 + i=68 + + + + someOptionalInt + + i=80 + i=68 + + + + someOptionalFloat + + i=80 + i=68 + + + + someOptionalStr + + i=80 + i=68 + + + + someOptionalByteArray + + i=80 + i=68 + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_primitive_attributes/expected_output/stdout.txt b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/concrete_class_with_primitive_attributes/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_primitive_attributes/input/snippets/name_prefix.txt b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/concrete_class_with_primitive_attributes/meta_model.py b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/meta_model.py new file mode 100644 index 00000000..ff0207fc --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_primitive_attributes/meta_model.py @@ -0,0 +1,41 @@ +class Something: + some_bool: bool + some_int: int + some_float: float + some_str: str + some_byte_array: bytearray + + some_optional_bool: Optional[bool] + some_optional_int: Optional[int] + some_optional_float: Optional[float] + some_optional_str: Optional[str] + some_optional_byte_array: Optional[bytearray] + + def __init__( + self, + some_bool: bool, + some_int: int, + some_float: float, + some_str: str, + some_byte_array: bytearray, + some_optional_bool: Optional[bool], + some_optional_int: Optional[int], + some_optional_float: Optional[float], + some_optional_str: Optional[str], + some_optional_byte_array: Optional[bytearray], + ) -> None: + self.some_bool = some_bool + self.some_int = some_int + self.some_float = some_float + self.some_str = some_str + self.some_byte_array = some_byte_array + self.some_optional_bool = some_optional_bool + self.some_optional_int = some_optional_int + self.some_optional_float = some_optional_float + self.some_optional_str = some_optional_str + self.some_optional_byte_array = some_optional_byte_array + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/concrete_class_with_string/expected_output/nodeset.xml b/test_data/opcua/test_main/concrete_class_with_string/expected_output/nodeset.xml new file mode 100644 index 00000000..7f403fe1 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_string/expected_output/nodeset.xml @@ -0,0 +1,154 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + AASSomethingType + + i=58 + ns=1;i=475297679 + + + + someStr + + i=78 + i=68 + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_string/expected_output/stdout.txt b/test_data/opcua/test_main/concrete_class_with_string/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_string/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/concrete_class_with_string/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/concrete_class_with_string/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_string/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/concrete_class_with_string/input/snippets/name_prefix.txt b/test_data/opcua/test_main/concrete_class_with_string/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_string/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/concrete_class_with_string/meta_model.py b/test_data/opcua/test_main/concrete_class_with_string/meta_model.py new file mode 100644 index 00000000..864b43ea --- /dev/null +++ b/test_data/opcua/test_main/concrete_class_with_string/meta_model.py @@ -0,0 +1,13 @@ +class Something: + some_str: str + + def __init__( + self, + some_str: str, + ) -> None: + self.some_str = some_str + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/constrained_primitive/expected_output/nodeset.xml b/test_data/opcua/test_main/constrained_primitive/expected_output/nodeset.xml new file mode 100644 index 00000000..ba299f22 --- /dev/null +++ b/test_data/opcua/test_main/constrained_primitive/expected_output/nodeset.xml @@ -0,0 +1,260 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + ConstraintUnlabeled290612035 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=290612035 + i=63 + + + At least 3 characters + + + + ConstraintUnlabeled701547320 + + i=85 + ns=1;i=1767447720 + + + + text + + ns=1;i=701547320 + i=63 + + + At most 9 characters. + + + + + + AASSomethingConstrainedDataType + + String + ns=1;i=290612035 + + + + AASMoreConstrainedDataType + + String + ns=1;i=701547320 + + + + + + AASContainerType + + i=58 + ns=1;i=1330725105 + + + + moreConstrained + + i=78 + i=68 + + + + diff --git a/test_data/opcua/test_main/constrained_primitive/expected_output/stdout.txt b/test_data/opcua/test_main/constrained_primitive/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/constrained_primitive/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/constrained_primitive/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/constrained_primitive/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/constrained_primitive/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/constrained_primitive/input/snippets/name_prefix.txt b/test_data/opcua/test_main/constrained_primitive/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/constrained_primitive/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/constrained_primitive/meta_model.py b/test_data/opcua/test_main/constrained_primitive/meta_model.py new file mode 100644 index 00000000..ed5176a8 --- /dev/null +++ b/test_data/opcua/test_main/constrained_primitive/meta_model.py @@ -0,0 +1,20 @@ +@invariant(lambda self: len(self) > 2, "At least 3 characters") +class Something_constrained(str): + pass + + +@invariant(lambda self: len(self) < 10, "At most 9 characters.") +class More_constrained(str): + pass + + +class Container: + more_constrained: More_constrained + + def __init__(self, more_constrained: More_constrained) -> None: + self.more_constrained = more_constrained + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/test_data/opcua/test_main/multiple_inheritance/expected_output/nodeset.xml b/test_data/opcua/test_main/multiple_inheritance/expected_output/nodeset.xml new file mode 100644 index 00000000..c8f58046 --- /dev/null +++ b/test_data/opcua/test_main/multiple_inheritance/expected_output/nodeset.xml @@ -0,0 +1,209 @@ + + + https://dummy.com + + + + + + + + i=1 + i=8 + i=11 + i=12 + i=15 + i=37 + i=40 + i=45 + i=46 + i=47 + i=17603 + + + Constraint + + i=58 + ns=1;i=833095329 + ns=1;i=1892455557 + + + + identifier + + i=68 + i=80 + + + + text + + i=68 + i=78 + + + + HasConstraint + + i=32 + + Constrains + + + + IAASSomethingAbstractType + + i=17602 + ns=1;i=608825403 + + + + someStr + + i=78 + i=68 + + + + + + IAASAnotherAbstractType + + i=17602 + ns=1;i=108311269 + + + + anotherStr + + i=78 + i=68 + + + + + + AASConcreteType + + i=58 + ns=1;i=902726832 + ns=1;i=871774015 + + + + diff --git a/test_data/opcua/test_main/multiple_inheritance/expected_output/stdout.txt b/test_data/opcua/test_main/multiple_inheritance/expected_output/stdout.txt new file mode 100644 index 00000000..2d755fc5 --- /dev/null +++ b/test_data/opcua/test_main/multiple_inheritance/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/opcua/test_main/multiple_inheritance/input/snippets/base_nodeset.xml b/test_data/opcua/test_main/multiple_inheritance/input/snippets/base_nodeset.xml new file mode 100644 index 00000000..2a3bf578 --- /dev/null +++ b/test_data/opcua/test_main/multiple_inheritance/input/snippets/base_nodeset.xml @@ -0,0 +1,18 @@ + + + + https://dummy.com + + + + + + + diff --git a/test_data/opcua/test_main/multiple_inheritance/input/snippets/name_prefix.txt b/test_data/opcua/test_main/multiple_inheritance/input/snippets/name_prefix.txt new file mode 100644 index 00000000..f9597998 --- /dev/null +++ b/test_data/opcua/test_main/multiple_inheritance/input/snippets/name_prefix.txt @@ -0,0 +1 @@ +AAS \ No newline at end of file diff --git a/test_data/opcua/test_main/multiple_inheritance/meta_model.py b/test_data/opcua/test_main/multiple_inheritance/meta_model.py new file mode 100644 index 00000000..5c1d4b0e --- /dev/null +++ b/test_data/opcua/test_main/multiple_inheritance/meta_model.py @@ -0,0 +1,25 @@ +@abstract +class Something_abstract: + some_str: str + + def __init__(self, some_str: str) -> None: + self.some_str = some_str + + +@abstract +class Another_abstract: + another_str: str + + def __init__(self, another_str: str) -> None: + self.another_str = another_str + + +class Concrete(Something_abstract, Another_abstract): + def __init__(self, some_str: str, another_str: str) -> None: + Something_abstract.__init__(self, some_str) + Another_abstract.__init__(self, another_str) + + +__version__ = "V198.4" + +__xml_namespace__ = "https://dummy/198/4" diff --git a/tests/opcua/__init__.py b/tests/opcua/__init__.py new file mode 100644 index 00000000..0dbb3f94 --- /dev/null +++ b/tests/opcua/__init__.py @@ -0,0 +1,3 @@ +# NOTE (mristin, 2022-04-08): +# We have to rename this directory so that it does not conflict with ``jsonschema`` +# which is a development dependency. diff --git a/tests/opcua/test_main.py b/tests/opcua/test_main.py new file mode 100644 index 00000000..e8def65c --- /dev/null +++ b/tests/opcua/test_main.py @@ -0,0 +1,121 @@ +# pylint: disable=missing-docstring + +import contextlib +import io +import os +import pathlib +import tempfile +import unittest + +import aas_core_meta.v3 + +import aas_core_codegen.main +import aas_core_codegen.opcua.main +import tests.common + + +class Test_against_recorded(unittest.TestCase): + _REPO_DIR = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent + PARENT_CASE_DIR = _REPO_DIR / "test_data" / "opcua" / "test_main" + + def test_against_meta_models(self) -> None: + assert ( + Test_against_recorded.PARENT_CASE_DIR.exists() + and Test_against_recorded.PARENT_CASE_DIR.is_dir() + ), f"{Test_against_recorded.PARENT_CASE_DIR=}" + + # fmt: off + test_cases = ( + tests.common.find_meta_models_in_parent_directory_of_test_cases_and_modules( + parent_case_dir=Test_against_recorded.PARENT_CASE_DIR, + aas_core_meta_modules=[ + aas_core_meta.v3 + ] + ) + ) + # fmt: on + + for test_case in test_cases: + snippets_dir = test_case.case_dir / "input/snippets" + assert snippets_dir.exists() and snippets_dir.is_dir(), snippets_dir + + expected_output_dir = test_case.case_dir / "expected_output" + + with contextlib.ExitStack() as exit_stack: + if tests.common.RERECORD: + output_dir = expected_output_dir + expected_output_dir.mkdir(exist_ok=True, parents=True) + else: + assert ( + expected_output_dir.exists() and expected_output_dir.is_dir() + ), expected_output_dir + + # pylint: disable=consider-using-with + tmp_dir = tempfile.TemporaryDirectory() + exit_stack.push(tmp_dir) + output_dir = pathlib.Path(tmp_dir.name) + + params = aas_core_codegen.main.Parameters( + model_path=test_case.model_path, + target=aas_core_codegen.main.Target.OPCUA, + snippets_dir=snippets_dir, + output_dir=output_dir, + ) + + stdout = io.StringIO() + stderr = io.StringIO() + + return_code = aas_core_codegen.main.execute( + params=params, stdout=stdout, stderr=stderr + ) + + if stderr.getvalue() != "": + raise AssertionError( + f"Expected no stderr on valid models, but got:\n" + f"{stderr.getvalue()}\n" + f"for the meta-model: {test_case.model_path}" + ) + + self.assertEqual( + 0, return_code, "Expected 0 return code on valid models" + ) + + stdout_pth = expected_output_dir / "stdout.txt" + normalized_stdout = stdout.getvalue().replace( + str(output_dir), "" + ) + + if tests.common.RERECORD: + stdout_pth.write_text(normalized_stdout, encoding="utf-8") + else: + self.assertEqual( + normalized_stdout, + stdout_pth.read_text(encoding="utf-8"), + stdout_pth, + ) + + for relevant_rel_pth in [ + pathlib.Path("nodeset.xml"), + ]: + expected_pth = expected_output_dir / relevant_rel_pth + output_pth = output_dir / relevant_rel_pth + + if not output_pth.exists(): + raise FileNotFoundError( + f"The output file is missing: {output_pth}" + ) + + if tests.common.RERECORD: + expected_pth.write_text( + output_pth.read_text(encoding="utf-8"), encoding="utf-8" + ) + else: + self.assertEqual( + expected_pth.read_text(encoding="utf-8"), + output_pth.read_text(encoding="utf-8"), + f"The files {expected_pth} and {output_pth} do not match.", + ) + + +if __name__ == "__main__": + unittest.main()