Commit ab146464 authored by oroulet's avatar oroulet

bugfix xml export import stucts

parent bf1c3ee8
......@@ -43,6 +43,7 @@ def new_struct_field(name, dtype, array=False, optional=False, description=""):
async def new_struct(server, idx, name, fields):
"""
simple way to create a new structure
return the created data type node and the list of encoding nodes
"""
dtype = await create_data_type(server.nodes.base_structure_type, idx, name)
enc = await create_encoding(dtype, idx, "Default Binary")
......@@ -59,7 +60,7 @@ async def new_struct(server, idx, name, fields):
sdef.DefaultEncodingId = enc.nodeid
await dtype.write_data_type_definition(sdef)
return dtype
return dtype, [enc]
async def new_enum(server, idx, name, values):
......
......@@ -142,7 +142,6 @@ class XmlExporter:
Returns:
"""
node_class = await node.read_node_class()
print("EXPORT", node, node_class)
if node_class is ua.NodeClass.Object:
await self.add_etree_object(node)
......@@ -319,7 +318,7 @@ class XmlExporter:
field_el.attrib['Datatype'] = field.DataType.to_string()
if field.ValueRank != -1:
field_el.attrib['ValueRank'] = str(int(field.ValueRank))
if field.ArrayDimensions != "":
if field.ArrayDimensions:
field_el.attrib['ArrayDimensions'] = ", ".join([str(i) for i in field.ArrayDimensions])
if field.IsOptional:
field_el.attrib['IsOptional'] = "true"
......
......@@ -20,20 +20,26 @@ class XmlImporter:
def __init__(self, server):
self.parser = None
self.server = server
self.namespaces: Dict[int, int] = {} #Dict[IndexInXml, IndexInServer]
self.namespaces: Dict[int, int] = {} # Dict[IndexInXml, IndexInServer]
self.aliases: Dict[str, ua.NodeId] = {}
self.refs = None
async def _map_namespaces(self, namespaces_uris):
async def _map_namespaces(self):
"""
creates a mapping between the namespaces in the xml file and in the server.
if not present the namespace is registered.
"""
namespaces = {}
for ns_index, ns_uri in enumerate(namespaces_uris):
ns_server_index = await self.server.register_namespace(ns_uri)
namespaces[ns_index + 1] = ns_server_index
return namespaces
xml_uris = self.parser.get_used_namespaces()
server_uris = await self.server.get_namespace_array()
namespaces_map = {}
for ns_index, ns_uri in enumerate(xml_uris):
ns_index += 1 # since namespaces start at 1 in xml files
if ns_uri in server_uris:
namespaces_map[ns_index] = server_uris.index(ns_uri)
else:
ns_server_index = await self.server.register_namespace(ns_uri)
namespaces_map[ns_index] = ns_server_index
return namespaces_map
def _map_aliases(self, aliases: dict):
"""
......@@ -44,7 +50,6 @@ class XmlImporter:
aliases_mapped[alias] = self._to_migrated_nodeid(node_id)
return aliases_mapped
async def _get_existing_model_in_namespace(self):
server_model_list = []
server_namespaces_node = await self.server.nodes.namespaces.get_children()
......@@ -85,7 +90,7 @@ class XmlImporter:
self.parser = XMLParser()
await self._check_required_models(xmlpath, xmlstring)
await self.parser.parse(xmlpath, xmlstring)
self.namespaces = await self._map_namespaces(self.parser.get_used_namespaces())
self.namespaces = await self._map_namespaces()
_logger.info("namespace map: %s", self.namespaces)
self.aliases = self._map_aliases(self.parser.get_aliases())
self.refs = []
......@@ -509,13 +514,14 @@ class XmlImporter:
sdef = ua.StructureDefinition()
if obj.parent:
sdef.BaseDataType = obj.parent
for data in obj.refs:
if data.reftype == self.server.nodes.HasEncoding.nodeid:
# looks likebinary encodingisthe firt one...can someone confirm?
sdef.DefaultEncodingId = data.target
for refdata in obj.refs:
if refdata.reftype == self.server.nodes.HasEncoding.nodeid:
# supposing that default encoding is the first one...
sdef.DefaultEncodingId = refdata.target
break
optional = False
for field in obj.definitions:
print("IMPORT FIEL", field.name, field.datatype)
f = ua.StructureField()
f.Name = field.name
f.DataType = field.datatype
......
......@@ -69,7 +69,7 @@ class NodeData:
class Field:
def __init__(self, data):
self.datatype = data.get("DataType", "")
self.datatype = data.get("Datatype", "")
self.name = data.get("Name")
self.dname = data.get("DisplayName", "")
self.optional = bool(data.get("IsOptional", False))
......
......@@ -546,8 +546,15 @@ class Server:
"""
Export defined nodes to xml
"""
uris = await self.get_namespace_array()
uris_to_export = {}
for node in nodes:
idx = node.nodeid.NamespaceIndex
if idx not in uris_to_export and idx < len(uris):
uris_to_export[idx] = uris[idx]
exp = XmlExporter(self)
await exp.build_etree(nodes)
await exp.build_etree(nodes, uris_to_export)
await exp.write_xml(path)
async def export_xml_by_ns(self, path: str, namespaces: list = None):
......
......@@ -1179,7 +1179,7 @@ async def test_custom_struct_with_optional_fields(opc):
async def test_custom_struct_of_struct(opc):
idx = 4
dtype = await new_struct(opc.opc, idx, "MySubStruct2", [
dtype, encs = await new_struct(opc.opc, idx, "MySubStruct2", [
new_struct_field("MyBool", ua.VariantType.Boolean),
new_struct_field("MyUInt32", ua.VariantType.UInt32),
])
......@@ -1202,7 +1202,7 @@ async def test_custom_struct_of_struct(opc):
async def test_custom_list_of_struct(opc):
idx = 4
dtype = await new_struct(opc.opc, idx, "MySubStruct3", [
dtype, encs = await new_struct(opc.opc, idx, "MySubStruct3", [
new_struct_field("MyBool", ua.VariantType.Boolean),
new_struct_field("MyUInt32", ua.VariantType.UInt32),
])
......@@ -1263,12 +1263,12 @@ async def test_two_times_enum(opc):
async def test_custom_struct_export(opc):
idx = 4
dtype = await new_struct(opc.opc, idx, "MyMyStructExport", [
dtype, encs = await new_struct(opc.opc, idx, "MyMyStructExport", [
new_struct_field("MyBool", ua.VariantType.Boolean),
new_struct_field("MyUInt32", ua.VariantType.UInt32, array=True),
])
await opc.opc.export_xml([dtype], "custom_struct_export.xml")
await opc.opc.export_xml([dtype, *encs], "custom_struct_export.xml")
async def test_custom_enum_export(opc):
......@@ -1279,6 +1279,25 @@ async def test_custom_enum_export(opc):
"toto",
"tutu",
])
path = "custom_enum_export.xml"
await opc.opc.export_xml([dtype], path )
await opc.opc.export_xml([dtype], "custom_enum_export.xml")
async def test_custom_enum_import(opc):
nodes = await opc.opc.import_xml("tests/custom_enum.xml")
nodes = [opc.opc.get_node(node) for node in nodes] # FIXME why does it return nodeids and not nodes?
node = nodes[0]
sdef = await node.read_data_type_definition()
assert sdef.Fields[0].Name == "titi"
await opc.opc.export_xml(nodes, "tests/custom_enum_v2.xml")
async def test_custom_struct_import(opc):
nodes = await opc.opc.import_xml("tests/custom_struct.xml")
nodes = [opc.opc.get_node(node) for node in nodes] # FIXME why does it return nodeids and not nodes?
node = nodes[0] #FIXME: make that more robust
sdef = await node.read_data_type_definition()
assert sdef.StructureType == ua.StructureType.Structure
assert sdef.Fields[0].Name == "MyBool"
await opc.opc.export_xml(nodes, "tests/custom_struct_v2.xml")
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