Commit b23fcfcb authored by olivier R-D's avatar olivier R-D

improve parsing of values in xml

parent 52dd77dd
......@@ -36,8 +36,8 @@ class NodeData(object):
# referencetype
self.inversename = ""
self.abstract = "false"
self.symmetric = "false"
self.abstract = False
self.symmetric = False
# datatype
self.definition = []
......@@ -51,6 +51,15 @@ class RefStruct(object):
self.target = None
class ExtObj(object):
def __init__(self):
self.typeid = None
self.objname = None
self.bodytype = None
self.body = {}
class XMLParser(object):
def __init__(self, xmlpath, server):
......@@ -194,6 +203,7 @@ class XMLParser(object):
obj.nodetype = name
for key, val in child.attrib.items():
self._set_attr(key, val, obj)
self.logger.info("\n Parsing node: %s %s", obj.nodeid, obj.browsename)
obj.displayname = obj.browsename # give a default value to display name
for el in child:
self._parse_tag(el, obj)
......@@ -211,7 +221,9 @@ class XMLParser(object):
elif key == "DataType":
obj.datatype = val
elif key == "IsAbstract":
obj.abstract = val
obj.abstract = self._to_bool(val)
elif key == "Executable":
obj.executable = self._to_bool(val)
elif key == "EventNotifier":
obj.eventnotifier = 1 if val == "1" else 0
elif key == "ValueRank":
......@@ -225,10 +237,15 @@ class XMLParser(object):
elif key == "UserAccessLevel":
obj.useraccesslevel = int(val)
elif key == "Symmetric":
obj.symmetric = True if val == "true" else False
obj.symmetric = self._to_bool(val)
else:
self.logger.info("Attribute not implemented: %s:%s", key, val)
def _to_bool(self, val):
if val in ("False, false"):
return False
else:
return True
def _parse_tag(self, el, obj):
tag = self._retag.match(el.tag).groups()[1]
......@@ -249,7 +266,9 @@ class XMLParser(object):
self.logger.info("Not implemented tag: %s", el)
def _parse_value(self, el, obj):
self.logger.info("Parsing value")
for val in el:
self.logger.info("tag %s", val.tag)
ntag = self._retag.match(val.tag).groups()[1]
obj.valuetype = ntag
if ntag in ("Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64"):
......@@ -271,11 +290,13 @@ class XMLParser(object):
elif ntag in ("Guid"):
self._parse_value(val, obj)
elif ntag == "ListOfExtensionObject":
obj.value, obj.valuetype = self._parse_list_of_extension_object(el)
obj.valuetype = "ExtensionObject"
obj.value = self._parse_list_of_extension_object(el)
elif ntag == "ListOfLocalizedText":
obj.valuetype = "LocalizedText"
obj.value = self._parse_list_of_localized_text(el)
else:
self.logger.info("Value type not implemented: %s", ntag)
self.logger.info("Value type not implemented: '%s', %s", ntag)
def _get_text(self, el):
txt = ""
......@@ -302,26 +323,28 @@ class XMLParser(object):
also the valuetype is returned. The valuetype is uax:ExtensionObject/*/tag()
'''
value = []
valuetype = None
for extension_object_list in el:
for extension_object in extension_object_list:
extension_object.find('Body')
for extension_object_part in extension_object:
ext = ExtObj()
ntag = self._retag.match(extension_object_part.tag).groups()[1]
if ntag == 'Body':
data = {}
if ntag == 'TypeId':
ntag = self._retag.match(extension_object_part.find('*').tag).groups()[1]
ext.typeid = self._get_text(extension_object_part)
elif ntag == 'Body':
ntag = self._retag.match(extension_object_part.find('*').tag).groups()[1]
valuetype = ntag
ext.objname = ntag
for body_item in extension_object_part.findall('*/*'):
ntag = self._retag.match(body_item.tag).groups()[1]
child = body_item.find('*')
if child is not None:
data[ntag] = self._get_text(child)
ext.body[ntag] = self._get_text(child)
else:
data[ntag] = self._get_text(body_item)
value.append(data)
return value, valuetype
ext.body[ntag] = self._get_text(body_item)
value.append(ext)
return value
def _parse_refs(self, el, obj):
for ref in el:
......
......@@ -3,6 +3,7 @@ Generate address space c++ code from xml file specification
xmlparser.py is a requirement. it is in opcua folder but to avoid importing all code, developer can link xmlparser.py in current directory
"""
import sys
import logging
# sys.path.insert(0, "..") # load local freeopcua implementation
#from opcua import xmlparser
import xmlparser
......@@ -21,7 +22,7 @@ class CodeGenerator(object):
sys.stderr.write("Generating Python code {} for XML file {}".format(self.output_path, self.input_path) + "\n")
self.output_file = open(self.output_path, "w")
self.make_header()
self.parser = xmlparser.XMLParser(self.input_path)
self.parser = xmlparser.XMLParser(self.input_path, None)
for node in self.parser:
if node.nodetype == 'UAObject':
self.make_object_code(node)
......@@ -53,8 +54,6 @@ It is automatically generated from opcfoundation.org schemas.
from opcua import ua
false = False #FIXME
true = True #FIXME
def create_standard_address_space_%s(server):
''' % (self.part))
......@@ -110,27 +109,48 @@ def create_standard_address_space_%s(server):
self.writecode(indent, 'server.add_nodes([node])')
self.make_refs_code(obj, indent)
def make_variable_code(self, obj):
indent = " "
self.writecode(indent)
self.make_node_code(obj, indent)
self.writecode(indent, 'attrs = ua.VariableAttributes()')
def make_common_variable_code(self, indent, obj):
if obj.desc:
self.writecode(indent, 'attrs.Description = ua.LocalizedText("{}")'.format(obj.desc))
self.writecode(indent, 'attrs.DisplayName = ua.LocalizedText("{}")'.format(obj.displayname))
self.writecode(indent, 'attrs.DataType = {}'.format(self.to_data_type(obj.datatype)))
if obj.value:
self.writecode(indent, 'attrs.Value = ua.Variant({}, ua.VariantType.{})'.format(self.to_value(obj.value), obj.valuetype))
if obj.value is not None:
if obj.valuetype == "ExtensionObject":
if isinstance(obj.value, (list, tuple)):
self.writecode(indent, 'value = []')
for ext in obj.value:
self.make_ext_obj_code(indent, ext)
self.writecode(indent, 'value.append(extobj)')
else:
self.make_ext_obj_code(indent, obj.value)
self.writecode(indent, 'value = extobj')
self.writecode(indent, 'attrs.Value = ua.Variant(value, ua.VariantType.ExtensionObject)')
else:
self.writecode(indent, 'attrs.Value = ua.Variant({}, ua.VariantType.{})'.format(self.to_value(obj.value), obj.valuetype))
if obj.rank:
self.writecode(indent, 'attrs.ValueRank = {}'.format(obj.rank))
if obj.accesslevel:
self.writecode(indent, 'attrs.AccessLevel = {}'.format(obj.accesslevel))
if obj.useraccesslevel:
self.writecode(indent, 'attrs.UserAccessLevel = {}'.format(obj.useraccesslevel))
if obj.dimensions:
self.writecode(indent, 'attrs.ArrayDimensions = {}'.format(obj.dimensions))
def make_ext_obj_code(self, indent, extobj):
self.writecode(indent, 'extobj = ua.{}()'.format(extobj.objname))
for name, val in extobj.body.items():
val = val.strip()
if val not in (None, ""):
self.writecode(indent, 'extobj.{} = "{}"'.format(name, val))
def make_variable_code(self, obj):
indent = " "
self.writecode(indent)
self.make_node_code(obj, indent)
self.writecode(indent, 'attrs = ua.VariableAttributes()')
if obj.minsample:
self.writecode(indent, 'attrs.MinimumSamplingInterval = {}'.format(obj.minsample))
if obj.dimensions:
self.writecode(indent, 'attrs.ArrayDimensions = '.format(obj.dimensions))
self.make_common_variable_code(indent, obj)
self.writecode(indent, 'node.NodeAttributes = attrs')
self.writecode(indent, 'server.add_nodes([node])')
self.make_refs_code(obj, indent)
......@@ -143,18 +163,9 @@ def create_standard_address_space_%s(server):
if obj.desc:
self.writecode(indent, 'attrs.Description = ua.LocalizedText("{}")'.format(obj.desc))
self.writecode(indent, 'attrs.DisplayName = ua.LocalizedText("{}")'.format(obj.displayname))
self.writecode(indent, 'attrs.DataType = {}'.format(self.to_data_type(obj.datatype)))
if obj.value:
self.writecode(indent, 'attrs.Value = {}'.format(self.to_value(obj.value)))
if obj.value:
self.writecode(indent, 'attrs.Value = {}'.format(self.to_value(obj.value)))
if obj.rank:
self.writecode(indent, 'attrs.ValueRank = {}'.format(obj.rank))
if obj.abstract:
self.writecode(indent, 'attrs.IsAbstract = {}'.format(obj.abstract))
print(obj.dimensions)
if obj.dimensions:
self.writecode(indent, 'attrs.ArrayDimensions = {}'.format(obj.dimensions))
self.make_common_variable_code(indent, obj)
self.writecode(indent, 'node.NodeAttributes = attrs')
self.writecode(indent, 'server.add_nodes([node])')
self.make_refs_code(obj, indent)
......@@ -174,14 +185,6 @@ def create_standard_address_space_%s(server):
if obj.desc:
self.writecode(indent, 'attrs.Description = ua.LocalizedText("{}")'.format(obj.desc))
self.writecode(indent, 'attrs.DisplayName = ua.LocalizedText("{}")'.format(obj.displayname))
if obj.accesslevel:
self.writecode(indent, 'attrs.AccessLevel = {}'.format(obj.accesslevel))
if obj.useraccesslevel:
self.writecode(indent, 'attrs.UserAccessLevel = {}'.format(obj.useraccesslevel))
if obj.minsample:
self.writecode(indent, 'attrs.MinimumSamplingInterval = {}'.format(obj.minsample))
if obj.dimensions:
self.writecode(indent, 'attrs.ArrayDimensions = {}'.format(obj.dimensions))
self.writecode(indent, 'node.NodeAttributes = attrs')
self.writecode(indent, 'server.add_nodes([node])')
self.make_refs_code(obj, indent)
......@@ -224,7 +227,7 @@ def create_standard_address_space_%s(server):
self.writecode(indent, "refs = []")
for ref in obj.refs:
self.writecode(indent, 'ref = ua.AddReferencesItem()')
self.writecode(indent, 'ref.IsForward = true')
self.writecode(indent, 'ref.IsForward = True')
self.writecode(indent, 'ref.ReferenceTypeId = {}'.format(self.to_ref_type(ref.reftype)))
self.writecode(indent, 'ref.SourceNodeId = ua.NodeId.from_string("{}")'.format(obj.nodeid))
self.writecode(indent, 'ref.TargetNodeClass = ua.NodeClass.DataType')
......@@ -245,6 +248,7 @@ def save_aspace_to_disk():
aspace.dump(path)
if __name__ == "__main__":
logging.basicConfig(level=logging.WARN)
for i in (3, 4, 5, 8, 9, 10, 11, 13):
xmlpath = "Opc.Ua.NodeSet2.Part{}.xml".format(str(i))
cpppath = "../opcua/server/standard_address_space/standard_address_space_part{}.py".format(str(i))
......
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