xmlparser.py
Go to the documentation of this file.
1 """
2 parse xml file from opcua-spec
3 """
4 import logging
5 import re
6 import sys
7 
8 import xml.etree.ElementTree as ET
9 
10 
11 def _to_bool(val):
12  return val in ("True", "true", "on", "On", "1")
13 
14 
15 def ua_type_to_python(val, uatype):
16  if uatype.startswith("Int") or uatype.startswith("UInt"):
17  return int(val)
18  elif uatype.lower().startswith("bool"):
19  return _to_bool(val)
20  elif uatype in ("Double", "Float"):
21  return float(val)
22  elif uatype == "String":
23  return val
24  elif uatype in ("Bytes", "Bytes", "ByteString", "ByteArray"):
25  if sys.version_info.major > 2:
26  return bytes(val, 'utf8')
27  else:
28  return val
29  else:
30  raise Exception("uatype nopt handled", uatype, " for val ", val)
31 
32 
33 class NodeData(object):
34 
35  def __init__(self):
36  self.nodetype = None
37  self.nodeid = None
38  self.browsename = None
39  self.displayname = None
40  self.symname = None # FIXME: this param is never used, why?
41  self.parent = None
42  self.parentlink = None
43  self.desc = ""
44  self.typedef = None
45  self.refs = []
46  self.nodeclass = None
47  self.eventnotifier = 0
48 
49  # variable
50  self.datatype = None
51  self.rank = -1 # check default value
52  self.value = None
53  self.valuetype = None
54  self.dimensions = None
55  self.accesslevel = None
56  self.useraccesslevel = None
57  self.minsample = None
58 
59  # referencetype
60  self.inversename = ""
61  self.abstract = False
62  self.symmetric = False
63 
64  # datatype
65  self.definition = []
66 
67  def __str__(self):
68  return "NodeData(nodeid:{0})".format(self.nodeid)
69  __repr__ = __str__
70 
71 
72 class RefStruct(object):
73 
74  def __init__(self):
75  self.reftype = None
76  self.forward = True
77  self.target = None
78 
79 
80 class ExtObj(object):
81 
82  def __init__(self):
83  self.typeid = None
84  self.objname = None
85  self.bodytype = None
86  self.body = {}
87 
88  def __str__(self):
89  return "ExtObj({0}, {1})".format(self.objname, self.body)
90  __repr__ = __str__
91 
92 
93 class XMLParser(object):
94 
95  def __init__(self, xmlpath):
96  self.logger = logging.getLogger(__name__)
97  self._retag = re.compile(r"(\{.*\})(.*)")
98  self.path = xmlpath
99 
100  self.tree = ET.parse(xmlpath)
101  self.root = self.tree.getroot()
102  # FIXME: hard to get these xml namespaces with ElementTree, we may have to shift to lxml
103  self.ns = {
104  'base': "http://opcfoundation.org/UA/2011/03/UANodeSet.xsd",
105  'uax': "http://opcfoundation.org/UA/2008/02/Types.xsd",
106  'xsd': "http://www.w3.org/2001/XMLSchema",
107  'xsi': "http://www.w3.org/2001/XMLSchema-instance"
108  }
109 
111  """
112  Return the used namespace uris in this import file
113  """
114  namespaces_uris = []
115  for child in self.root:
116  tag = self._retag.match(child.tag).groups()[1]
117  if tag == 'NamespaceUris':
118  namespaces_uris = [ns_element.text for ns_element in child]
119  break
120  return namespaces_uris
121 
122  def get_aliases(self):
123  """
124  Return the used node aliases in this import file
125  """
126  aliases = {}
127  for child in self.root:
128  tag = self._retag.match(child.tag).groups()[1]
129  if tag == 'Aliases':
130  for el in child:
131  aliases[el.attrib["Alias"]] = el.text
132  break
133  return aliases
134 
135  def get_node_datas(self):
136  nodes = []
137  for child in self.root:
138  tag = self._retag.match(child.tag).groups()[1]
139  if tag not in ["Aliases", "NamespaceUris", "Extensions", "Models"]: # these XML tags don't contain nodes
140  node = self._parse_node(tag, child)
141  nodes.append(node)
142  return nodes
143 
144  def _parse_node(self, nodetype, child):
145  """
146  Parse a XML node and create a NodeData object.
147  """
148  obj = NodeData()
149  obj.nodetype = nodetype
150  for key, val in child.attrib.items():
151  self._set_attr(key, val, obj)
152  self.logger.info("Parsing node: %s %s", obj.nodeid, obj.browsename)
153  obj.displayname = obj.browsename # give a default value to display name
154  for el in child:
155  self._parse_attr(el, obj)
156  return obj
157 
158  def _set_attr(self, key, val, obj):
159  if key == "NodeId":
160  obj.nodeid = val
161  elif key == "BrowseName":
162  obj.browsename = val
163  elif key == "SymbolicName":
164  obj.symname = val
165  elif key == "ParentNodeId":
166  obj.parent = val
167  elif key == "DataType":
168  obj.datatype = val
169  elif key == "IsAbstract":
170  obj.abstract = _to_bool(val)
171  elif key == "Executable":
172  obj.executable = _to_bool(val)
173  elif key == "EventNotifier":
174  obj.eventnotifier = int(val)
175  elif key == "ValueRank":
176  obj.rank = int(val)
177  elif key == "ArrayDimensions":
178  obj.dimensions = [int(i) for i in val.split(",")]
179  elif key == "MinimumSamplingInterval":
180  obj.minsample = int(val)
181  elif key == "AccessLevel":
182  obj.accesslevel = int(val)
183  elif key == "UserAccessLevel":
184  obj.useraccesslevel = int(val)
185  elif key == "Symmetric":
186  obj.symmetric = _to_bool(val)
187  else:
188  self.logger.info("Attribute not implemented: %s:%s", key, val)
189 
190  def _parse_attr(self, el, obj):
191  tag = self._retag.match(el.tag).groups()[1]
192 
193  if tag == "DisplayName":
194  obj.displayname = el.text
195  elif tag == "Description":
196  obj.desc = el.text
197  elif tag == "References":
198  self._parse_refs(el, obj)
199  elif tag == "Value":
200  self._parse_value(el, obj)
201  elif tag == "InverseName":
202  obj.inversename = el.text
203  elif tag == "Definition":
204  for field in el:
205  obj.definition.append(field)
206  else:
207  self.logger.info("Not implemented tag: %s", el)
208 
209  def _parse_value(self, val_el, obj):
210  child_el = val_el.find(".//") # should be only one child
211  if child_el is not None:
212  ntag = self._retag.match(child_el.tag).groups()[1]
213  else:
214  ntag = "Null"
215  obj.valuetype = ntag
216 
217  if ntag in ("Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64"):
218  obj.value = int(child_el.text)
219  elif ntag in ("Float", "Double"):
220  obj.value = float(child_el.text)
221  elif ntag == "Boolean":
222  obj.value = _to_bool(child_el.text)
223  elif ntag in ("ByteString", "String"):
224  mytext = child_el.text
225  if mytext is None: # support importing null strings
226  mytext = ""
227  mytext = mytext.replace('\n', '').replace('\r', '')
228  obj.value = mytext
229  elif ntag == "DateTime":
230  obj.value = child_el.text
231  elif ntag == "Guid":
232  self._parse_value(child_el, obj)
233  obj.valuetype = obj.datatype # override parsed string type to guid
234  elif ntag == "LocalizedText":
235  obj.value = self._parse_body(child_el)
236  elif ntag == "NodeId":
237  id_el = child_el.find("uax:Identifier", self.ns)
238  if id_el is not None:
239  obj.value = id_el.text
240  elif ntag == "ListOfExtensionObject":
241  obj.value = self._parse_list_of_extension_object(child_el)
242  elif ntag == "ListOfLocalizedText":
243  obj.value = self._parse_list_of_localized_text(child_el)
244  elif ntag.startswith("ListOf"):
245  obj.value = self._parse_list(child_el)
246  elif ntag == "ExtensionObject":
247  obj.value = self._parse_ext_obj(child_el)
248  elif ntag == "Null":
249  obj.value = None
250  else:
251  self.logger.warning("Parsing value of type '%s' not implemented", ntag)
252 
253  def _get_text(self, el):
254  txtlist = [txt.strip() for txt in el.itertext()]
255  return "".join(txtlist)
256 
257  def _parse_list(self, el):
258  value = []
259  for val_el in el:
260  ntag = self._retag.match(val_el.tag).groups()[1]
261  if ntag.startswith("ListOf"):
262  val = self._parse_list(val_el)
263  else:
264  val = ua_type_to_python(val_el.text, ntag)
265  value.append(val)
266  return value
267 
269  value = []
270  for localized_text in el:
271  ntag = self._retag.match(localized_text.tag).groups()[1]
272  for child in localized_text:
273  ntag = self._retag.match(child.tag).groups()[1]
274  if ntag == 'Text':
275  value.append(self._get_text(child))
276  return value
277 
279  """
280  Parse a uax:ListOfExtensionObject Value
281  Return an list of ExtObj
282  """
283  value = []
284  for extension_object in el:
285  ext_obj = self._parse_ext_obj(extension_object)
286  value.append(ext_obj)
287  return value
288 
289  def _parse_ext_obj(self, el):
290  ext = ExtObj()
291  for extension_object_part in el:
292  ntag = self._retag.match(extension_object_part.tag).groups()[1]
293  if ntag == 'TypeId':
294  ntag = self._retag.match(extension_object_part.find('*').tag).groups()[1]
295  ext.typeid = self._get_text(extension_object_part)
296  elif ntag == 'Body':
297  ext.objname = self._retag.match(extension_object_part.find('*').tag).groups()[1]
298  ext.body = self._parse_body(extension_object_part)
299  else:
300  print("Uknown ndtag", ntag)
301  return ext
302 
303  def _parse_body(self, el):
304  body = []
305  for body_item in el:
306  otag = self._retag.match(body_item.tag).groups()[1]
307  childs = [i for i in body_item]
308  if not childs:
309  val = self._get_text(body_item)
310  else:
311  val = self._parse_body(body_item)
312  if val:
313  body.append((otag, val))
314  return body
315 
316  def _parse_refs(self, el, obj):
317  for ref in el:
318  if ref.attrib["ReferenceType"] == "HasTypeDefinition":
319  obj.typedef = ref.text
320  elif "IsForward" in ref.attrib and ref.attrib["IsForward"] in ("false", "False"):
321  # if obj.parent:
322  # sys.stderr.write("Parent is already set with: "+ obj.parent + " " + ref.text + "\n")
323  obj.parent = ref.text
324  obj.parentlink = ref.attrib["ReferenceType"]
325  else:
326  struct = RefStruct()
327  if "IsForward" in ref.attrib:
328  struct.forward = ref.attrib["IsForward"]
329  struct.target = ref.text
330  struct.reftype = ref.attrib["ReferenceType"]
331  obj.refs.append(struct)
def __init__(self, xmlpath)
Definition: xmlparser.py:95
def _set_attr(self, key, val, obj)
Definition: xmlparser.py:158
def _parse_list_of_localized_text(self, el)
Definition: xmlparser.py:268
def _parse_attr(self, el, obj)
Definition: xmlparser.py:190
def _parse_value(self, val_el, obj)
Definition: xmlparser.py:209
def _parse_node(self, nodetype, child)
Definition: xmlparser.py:144
def ua_type_to_python(val, uatype)
Definition: xmlparser.py:15
def _parse_refs(self, el, obj)
Definition: xmlparser.py:316
def _parse_list_of_extension_object(self, el)
Definition: xmlparser.py:278


ros_opcua_impl_python_opcua
Author(s): Denis Štogl , Daniel Draper
autogenerated on Tue Jan 19 2021 03:12:44