Commit f08c39b8 authored by oroulet's avatar oroulet Committed by oroulet

import substructures from xml

parent 736373dc
......@@ -86,7 +86,9 @@ class {name}:
elif field.DataType in ua.enums_by_datatype:
uatype = ua.enums_by_datatype[field.DataType].__name__
else:
raise RuntimeError(f"Unknown datatype for field: {field} in structure:{name}")
#FIXME: we are probably missing many custom tyes here based on builtin types
#maybe we can use ua_utils.get_base_data_type()
raise RuntimeError(f"Unknown datatype for field: {field} in structure:{name}, please report")
if field.ValueRank >= 1 and uatype == 'Char':
uatype = 'String'
uatypes.append((field, uatype))
......@@ -177,6 +179,7 @@ async def load_data_type_definitions(server, base_node=None):
base_node = server.nodes.base_structure_type
dtypes = []
await _recursive_parse(server, base_node, dtypes)
dtypes.sort()
for dts in dtypes:
try:
env = await _generate_object(dts.name, dts.sdef)
......
......@@ -12,13 +12,15 @@ from .xmlparser import XMLParser, ua_type_to_python
from ..ua.uaerrors import UaError
_logger = logging.getLogger(__name__)
class XmlImporter:
def __init__(self, server):
self.logger = logging.getLogger(__name__)
self.parser = None
self.server = server
self.namespaces: Dict[int, int] = {}
self.namespaces: Dict[int, int] = {} #Dict[IndexInXml, IndexInServer]
self.aliases: Dict[str, ua.NodeId] = {}
self.refs = None
......@@ -39,14 +41,14 @@ class XmlImporter:
"""
aliases_mapped = {}
for alias, node_id in aliases.items():
aliases_mapped[alias] = self.to_nodeid(node_id)
aliases_mapped[alias] = self._to_migrated_nodeid(node_id)
return aliases_mapped
async def import_xml(self, xmlpath=None, xmlstring=None):
"""
import xml and return added nodes
"""
self.logger.info("Importing XML file %s", xmlpath)
_logger.info("Importing XML file %s", xmlpath)
self.parser = XMLParser()
await self.parser.parse(xmlpath, xmlstring)
self.namespaces = await self._map_namespaces(self.parser.get_used_namespaces())
......@@ -60,13 +62,13 @@ class XmlImporter:
try:
node = await self._add_node_data(nodedata)
except Exception:
self.logger.warning("failure adding node %s", nodedata)
_logger.warning("failure adding node %s", nodedata)
raise
nodes.append(node)
self.refs, remaining_refs = [], self.refs
await self._add_references(remaining_refs)
if len(self.refs):
self.logger.warning("The following references could not be imported and are probably broken: %s", self.refs)
_logger.warning("The following references could not be imported and are probably broken: %s", self.refs)
return nodes
async def _add_node_data(self, nodedata) -> "Node":
......@@ -104,15 +106,23 @@ class XmlImporter:
def make_objects(self, node_data):
new_nodes = []
for node_datum in node_data:
node_datum.nodeid = ua.NodeId.from_string(node_datum.nodeid)
node_datum.nodeid = self._to_migrated_nodeid(node_datum.nodeid)
node_datum.browsename = ua.QualifiedName.from_string(node_datum.browsename)
if node_datum.parent:
node_datum.parent = ua.NodeId.from_string(node_datum.parent)
node_datum.parent = self._to_migrated_nodeid(node_datum.parent)
if node_datum.parentlink:
node_datum.parentlink = self._to_nodeid(node_datum.parentlink)
node_datum.parentlink = self._to_migrated_nodeid(node_datum.parentlink)
if node_datum.typedef:
node_datum.typedef = self._to_nodeid(node_datum.typedef)
node_datum.typedef = self._to_migrated_nodeid(node_datum.typedef)
if node_datum.datatype:
node_datum.datatype = self._to_migrated_nodeid(node_datum.datatype)
new_nodes.append(node_datum)
for ref in node_datum.refs:
ref.reftype = self._to_migrated_nodeid(ref.reftype)
ref.target = self._to_migrated_nodeid(ref.target)
for field in node_datum.definitions:
if field.datatype:
field.datatype = self._to_migrated_nodeid(field.datatype)
return new_nodes
def _migrate_ns(self, nodeid: ua.NodeId) -> ua.NodeId:
......@@ -132,7 +142,7 @@ class XmlImporter:
node = ua.AddNodesItem()
node.RequestedNewNodeId = self._migrate_ns(obj.nodeid)
node.BrowseName = self._migrate_ns(obj.browsename)
self.logger.info("Importing xml node (%s, %s) as (%s %s)", obj.browsename,
_logger.info("Importing xml node (%s, %s) as (%s %s)", obj.browsename,
obj.nodeid, node.BrowseName, node.RequestedNewNodeId)
node.NodeClass = getattr(ua.NodeClass, obj.nodetype[2:])
if obj.parent and obj.parentlink:
......@@ -142,6 +152,10 @@ class XmlImporter:
node.TypeDefinition = self._migrate_ns(obj.typedef)
return node
def _to_migrated_nodeid(self, nodeid: Union[ua.NodeId, None, str]) -> ua.NodeId:
nodeid = self._to_nodeid(nodeid)
return self._migrate_ns(nodeid)
def _to_nodeid(self, nodeid: Union[ua.NodeId, None, str]) -> ua.NodeId:
if isinstance(nodeid, ua.NodeId):
return nodeid
......@@ -157,9 +171,6 @@ class XmlImporter:
else:
return ua.NodeId(getattr(ua.ObjectIds, nodeid))
def to_nodeid(self, nodeid: Union[ua.NodeId, None, str]) -> ua.NodeId:
return self._migrate_ns(self._to_nodeid(nodeid))
async def add_object(self, obj):
node = self._get_node(obj)
attrs = ua.ObjectAttributes()
......@@ -192,7 +203,7 @@ class XmlImporter:
if obj.desc:
attrs.Description = ua.LocalizedText(obj.desc)
attrs.DisplayName = ua.LocalizedText(obj.displayname)
attrs.DataType = self.to_nodeid(obj.datatype)
attrs.DataType = obj.datatype
if obj.value is not None:
attrs.Value = self._add_variable_value(obj,)
if obj.rank:
......@@ -274,7 +285,7 @@ class XmlImporter:
"""
Returns the value for a Variable based on the objects value type.
"""
self.logger.debug("Setting value with type %s and value %s", obj.valuetype, obj.value)
_logger.debug("Setting value with type %s and value %s", obj.valuetype, obj.value)
if obj.valuetype == 'ListOfExtensionObject':
values = []
for ext in obj.value:
......@@ -306,7 +317,7 @@ class XmlImporter:
elif name == "Locale":
ltext.Locale = val
else:
self.logger.warning("While parsing localizedText value, unkown element: %s with val: %s", name, val)
_logger.warning("While parsing localizedText value, unkown element: %s with val: %s", name, val)
return ua.Variant(ltext, ua.VariantType.LocalizedText)
elif obj.valuetype == 'NodeId':
return ua.Variant(ua.NodeId.from_string(obj.value))
......@@ -319,7 +330,7 @@ class XmlImporter:
if obj.desc:
attrs.Description = ua.LocalizedText(obj.desc)
attrs.DisplayName = ua.LocalizedText(obj.displayname)
attrs.DataType = self.to_nodeid(obj.datatype)
attrs.DataType = obj.datatype
if obj.value and len(obj.value) == 1:
attrs.Value = obj.value[0]
if obj.rank:
......@@ -380,14 +391,20 @@ class XmlImporter:
attrs.DisplayName = ua.LocalizedText(obj.displayname)
if obj.abstract:
attrs.IsAbstract = obj.abstract
if obj.definitions and obj.parent == ua.NodeId(29):
attrs.DataTypeDefinition = self._get_edef(node, obj)
pass
elif obj.definitions and obj.parent == ua.NodeId(22):
#FIXME need better check for subclasses!!
attrs.DataTypeDefinition = self._get_sdef(node, obj)
else:
if not obj.definitions:
print("NOT DEFINITON", obj.parent, obj)
else:
if obj.parent == self.server.nodes.enum_data_type:
attrs.DataTypeDefinition = self._get_edef(node, obj)
elif obj.parent == self.server.nodes.base_structure_type:
attrs.DataTypeDefinition = self._get_sdef(node, obj)
else:
parent_node = self.server.get_node(obj.parent)
path = await parent_node.get_path()
if self.server.nodes.base_structure_type in path:
attrs.DataTypeDefinition = self._get_sdef(node, obj)
else:
_logger.warning("%s has datatypedefinition and path %s but we could not find out if this is a struct", obj, path)
node.NodeAttributes = attrs
res = await self._get_server().add_nodes([node])
res[0].StatusCode.check()
......@@ -401,9 +418,9 @@ class XmlImporter:
for data in obj.refs:
ref = ua.AddReferencesItem()
ref.IsForward = data.forward
ref.ReferenceTypeId = self.to_nodeid(data.reftype)
ref.SourceNodeId = self._migrate_ns(obj.nodeid)
ref.TargetNodeId = self.to_nodeid(data.target)
ref.ReferenceTypeId = data.reftype
ref.SourceNodeId = obj.nodeid
ref.TargetNodeId = data.target
refs.append(ref)
await self._add_references(refs)
......@@ -430,17 +447,17 @@ class XmlImporter:
return None
sdef = ua.StructureDefinition()
if obj.parent:
sdef.BaseDataType = self.to_nodeid(obj.parent)
sdef.BaseDataType = obj.parent
for data in obj.refs:
if data.reftype == "HasEncoding":
# looks likebinary encodingisthe firt one...can someone confirm?
sdef.DefaultEncodingId = self.to_nodeid(data.target)
sdef.DefaultEncodingId = data.target
break
optional = False
for field in obj.definitions:
f = ua.StructureField()
f.Name = field.name
f.DataType = self.to_nodeid(field.datatype)
f.DataType = field.datatype
f.ValueRank = field.valuerank
f.IsOptional = field.optional
if f.IsOptional:
......@@ -468,7 +485,7 @@ class XmlImporter:
all_node_ids = [data.nodeid for data in ndatas]
while ndatas:
for ndata in ndatas[:]:
if ndata.nodeid.NamespaceIndex not in self.namespaces or \
if ndata.nodeid.NamespaceIndex not in self.namespaces.values() or \
ndata.parent is None or \
ndata.parent not in all_node_ids:
sorted_ndatas.append(ndata)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment