nodes.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. ### This Source Code Form is subject to the terms of the Mozilla Public
  4. ### License, v. 2.0. If a copy of the MPL was not distributed with this
  5. ### file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. ### Copyright 2014-2015 (c) TU-Dresden (Author: Chris Iatrou)
  7. ### Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  8. ### Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
  9. import sys
  10. import logging
  11. from datatypes import *
  12. __all__ = ['Reference', 'RefOrAlias', 'Node', 'ReferenceTypeNode',
  13. 'ObjectNode', 'VariableNode', 'VariableTypeNode',
  14. 'MethodNode', 'ObjectTypeNode', 'DataTypeNode', 'ViewNode']
  15. logger = logging.getLogger(__name__)
  16. if sys.version_info[0] >= 3:
  17. # strings are already parsed to unicode
  18. def unicode(s):
  19. return s
  20. class Reference(object):
  21. # all either nodeids or strings with an alias
  22. def __init__(self, source, referenceType, target, isForward):
  23. self.source = source
  24. self.referenceType = referenceType
  25. self.target = target
  26. self.isForward = isForward
  27. def __str__(self):
  28. retval = str(self.source)
  29. if not self.isForward:
  30. retval = retval + "<"
  31. retval = retval + "--[" + str(self.referenceType) + "]--"
  32. if self.isForward:
  33. retval = retval + ">"
  34. return retval + str(self.target)
  35. def __repr__(self):
  36. return str(self)
  37. def __eq__(self, other):
  38. return str(self) == str(other)
  39. def __ne__(self, other):
  40. return not self.__eq__(other)
  41. def __hash__(self):
  42. return hash(str(self))
  43. def RefOrAlias(s):
  44. try:
  45. return NodeId(s)
  46. except Exception:
  47. return s
  48. class Node(object):
  49. def __init__(self):
  50. self.id = None
  51. self.browseName = None
  52. self.displayName = None
  53. self.description = None
  54. self.symbolicName = None
  55. self.writeMask = None
  56. self.userWriteMask = None
  57. self.references = set()
  58. self.hidden = False
  59. self.modelUri = None
  60. self.parent = None
  61. self.parentReference = None
  62. def __str__(self):
  63. return self.__class__.__name__ + "(" + str(self.id) + ")"
  64. def __repr__(self):
  65. return str(self)
  66. def sanitize(self):
  67. pass
  68. def parseXML(self, xmlelement):
  69. for idname in ['NodeId', 'NodeID', 'nodeid']:
  70. if xmlelement.hasAttribute(idname):
  71. self.id = RefOrAlias(xmlelement.getAttribute(idname))
  72. for (at, av) in xmlelement.attributes.items():
  73. if at == "BrowseName":
  74. self.browseName = QualifiedName(av)
  75. elif at == "DisplayName":
  76. self.displayName = LocalizedText(av)
  77. elif at == "Description":
  78. self.description = LocalizedText(av)
  79. elif at == "WriteMask":
  80. self.writeMask = int(av)
  81. elif at == "UserWriteMask":
  82. self.userWriteMask = int(av)
  83. elif at == "EventNotifier":
  84. self.eventNotifier = int(av)
  85. elif at == "SymbolicName":
  86. self.symbolicName = String(av)
  87. for x in xmlelement.childNodes:
  88. if x.nodeType != x.ELEMENT_NODE:
  89. continue
  90. if x.firstChild:
  91. if x.localName == "BrowseName":
  92. self.browseName = QualifiedName(x.firstChild.data)
  93. elif x.localName == "DisplayName":
  94. self.displayName = LocalizedText(x.firstChild.data)
  95. elif x.localName == "Description":
  96. self.description = LocalizedText(x.firstChild.data)
  97. elif x.localName == "WriteMask":
  98. self.writeMask = int(unicode(x.firstChild.data))
  99. elif x.localName == "UserWriteMask":
  100. self.userWriteMask = int(unicode(x.firstChild.data))
  101. if x.localName == "References":
  102. self.parseXMLReferences(x)
  103. def parseXMLReferences(self, xmlelement):
  104. for ref in xmlelement.childNodes:
  105. if ref.nodeType != ref.ELEMENT_NODE:
  106. continue
  107. source = RefOrAlias(str(self.id)) # deep-copy of the nodeid
  108. target = RefOrAlias(ref.firstChild.data)
  109. reftype = None
  110. forward = True
  111. for (at, av) in ref.attributes.items():
  112. if at == "ReferenceType":
  113. reftype = RefOrAlias(av)
  114. elif at == "IsForward":
  115. forward = not "false" in av.lower()
  116. self.references.add(Reference(source, reftype, target, forward))
  117. def getParentReference(self, parentreftypes):
  118. # HasSubtype has precedence
  119. for ref in self.references:
  120. if ref.referenceType == NodeId("ns=0;i=45") and not ref.isForward:
  121. return ref
  122. for ref in self.references:
  123. if ref.referenceType in parentreftypes and not ref.isForward:
  124. return ref
  125. return None
  126. def popTypeDef(self):
  127. for ref in self.references:
  128. if ref.referenceType.i == 40 and ref.isForward:
  129. self.references.remove(ref)
  130. return ref
  131. return Reference(NodeId(), NodeId(), NodeId(), False)
  132. def replaceAliases(self, aliases):
  133. if str(self.id) in aliases:
  134. self.id = NodeId(aliases[self.id])
  135. if isinstance(self, VariableNode) or isinstance(self, VariableTypeNode):
  136. if str(self.dataType) in aliases:
  137. self.dataType = NodeId(aliases[self.dataType])
  138. new_refs = set()
  139. for ref in self.references:
  140. if str(ref.source) in aliases:
  141. ref.source = NodeId(aliases[ref.source])
  142. if str(ref.target) in aliases:
  143. ref.target = NodeId(aliases[ref.target])
  144. if str(ref.referenceType) in aliases:
  145. ref.referenceType = NodeId(aliases[ref.referenceType])
  146. new_refs.add(ref)
  147. self.references = new_refs
  148. def replaceNamespaces(self, nsMapping):
  149. self.id.ns = nsMapping[self.id.ns]
  150. self.browseName.ns = nsMapping[self.browseName.ns]
  151. if hasattr(self, 'dataType') and isinstance(self.dataType, NodeId):
  152. self.dataType.ns = nsMapping[self.dataType.ns]
  153. new_refs = set()
  154. for ref in self.references:
  155. ref.source.ns = nsMapping[ref.source.ns]
  156. ref.target.ns = nsMapping[ref.target.ns]
  157. ref.referenceType.ns = nsMapping[ref.referenceType.ns]
  158. new_refs.add(ref)
  159. self.references = new_refs
  160. class ReferenceTypeNode(Node):
  161. def __init__(self, xmlelement=None):
  162. Node.__init__(self)
  163. self.isAbstract = False
  164. self.symmetric = False
  165. self.inverseName = ""
  166. if xmlelement:
  167. ReferenceTypeNode.parseXML(self, xmlelement)
  168. def parseXML(self, xmlelement):
  169. Node.parseXML(self, xmlelement)
  170. for (at, av) in xmlelement.attributes.items():
  171. if at == "Symmetric":
  172. self.symmetric = "false" not in av.lower()
  173. elif at == "InverseName":
  174. self.inverseName = str(av)
  175. elif at == "IsAbstract":
  176. self.isAbstract = "false" not in av.lower()
  177. for x in xmlelement.childNodes:
  178. if x.nodeType == x.ELEMENT_NODE:
  179. if x.localName == "InverseName" and x.firstChild:
  180. self.inverseName = str(unicode(x.firstChild.data))
  181. class ObjectNode(Node):
  182. def __init__(self, xmlelement=None):
  183. Node.__init__(self)
  184. self.eventNotifier = 0
  185. if xmlelement:
  186. ObjectNode.parseXML(self, xmlelement)
  187. def parseXML(self, xmlelement):
  188. Node.parseXML(self, xmlelement)
  189. for (at, av) in xmlelement.attributes.items():
  190. if at == "EventNotifier":
  191. self.eventNotifier = int(av)
  192. class VariableNode(Node):
  193. def __init__(self, xmlelement=None):
  194. Node.__init__(self)
  195. self.dataType = None
  196. self.valueRank = None
  197. self.arrayDimensions = []
  198. # Set access levels to read by default
  199. self.accessLevel = 1
  200. self.userAccessLevel = 1
  201. self.minimumSamplingInterval = 0.0
  202. self.historizing = False
  203. self.value = None
  204. self.xmlValueDef = None
  205. if xmlelement:
  206. VariableNode.parseXML(self, xmlelement)
  207. def parseXML(self, xmlelement):
  208. Node.parseXML(self, xmlelement)
  209. for (at, av) in xmlelement.attributes.items():
  210. if at == "ValueRank":
  211. self.valueRank = int(av)
  212. elif at == "AccessLevel":
  213. self.accessLevel = int(av)
  214. elif at == "UserAccessLevel":
  215. self.userAccessLevel = int(av)
  216. elif at == "MinimumSamplingInterval":
  217. self.minimumSamplingInterval = float(av)
  218. elif at == "DataType":
  219. self.dataType = RefOrAlias(av)
  220. elif at == "ArrayDimensions":
  221. self.arrayDimensions = av.split(",")
  222. elif at == "Historizing":
  223. self.historizing = "false" not in av.lower()
  224. for x in xmlelement.childNodes:
  225. if x.nodeType != x.ELEMENT_NODE:
  226. continue
  227. if x.localName == "Value":
  228. self.xmlValueDef = x
  229. elif x.localName == "DataType":
  230. self.dataType = RefOrAlias(av)
  231. elif x.localName == "ValueRank":
  232. self.valueRank = int(unicode(x.firstChild.data))
  233. elif x.localName == "ArrayDimensions" and len(self.arrayDimensions) == 0:
  234. elements = x.getElementsByTagName("ListOfUInt32");
  235. if len(elements):
  236. for idx, v in enumerate(elements[0].getElementsByTagName("UInt32")):
  237. self.arrayDimensions.append(v.firstChild.data)
  238. elif x.localName == "AccessLevel":
  239. self.accessLevel = int(unicode(x.firstChild.data))
  240. elif x.localName == "UserAccessLevel":
  241. self.userAccessLevel = int(unicode(x.firstChild.data))
  242. elif x.localName == "MinimumSamplingInterval":
  243. self.minimumSamplingInterval = float(unicode(x.firstChild.data))
  244. elif x.localName == "Historizing":
  245. self.historizing = "false" not in x.lower()
  246. def allocateValue(self, nodeset):
  247. dataTypeNode = nodeset.getDataTypeNode(self.dataType)
  248. if dataTypeNode is None:
  249. return False
  250. # FIXME: Don't build at all or allocate "defaults"? I'm for not building at all.
  251. if self.xmlValueDef is None:
  252. #logger.warn("Variable " + self.browseName() + "/" + str(self.id()) + " is not initialized. No memory will be allocated.")
  253. return False
  254. self.value = Value()
  255. self.value.parseXMLEncoding(self.xmlValueDef, dataTypeNode, self)
  256. return True
  257. class VariableTypeNode(VariableNode):
  258. def __init__(self, xmlelement=None):
  259. VariableNode.__init__(self)
  260. self.isAbstract = False
  261. if xmlelement:
  262. VariableTypeNode.parseXML(self, xmlelement)
  263. def parseXML(self, xmlelement):
  264. VariableNode.parseXML(self, xmlelement)
  265. for (at, av) in xmlelement.attributes.items():
  266. if at == "IsAbstract":
  267. self.isAbstract = "false" not in av.lower()
  268. for x in xmlelement.childNodes:
  269. if x.nodeType != x.ELEMENT_NODE:
  270. continue
  271. if x.localName == "IsAbstract":
  272. self.isAbstract = "false" not in av.lower()
  273. class MethodNode(Node):
  274. def __init__(self, xmlelement=None):
  275. Node.__init__(self)
  276. self.executable = True
  277. self.userExecutable = True
  278. self.methodDecalaration = None
  279. if xmlelement:
  280. MethodNode.parseXML(self, xmlelement)
  281. def parseXML(self, xmlelement):
  282. Node.parseXML(self, xmlelement)
  283. for (at, av) in xmlelement.attributes.items():
  284. if at == "Executable":
  285. self.executable = "false" not in av.lower()
  286. if at == "UserExecutable":
  287. self.userExecutable = "false" not in av.lower()
  288. if at == "MethodDeclarationId":
  289. self.methodDeclaration = str(av)
  290. class ObjectTypeNode(Node):
  291. def __init__(self, xmlelement=None):
  292. Node.__init__(self)
  293. self.isAbstract = False
  294. if xmlelement:
  295. ObjectTypeNode.parseXML(self, xmlelement)
  296. def parseXML(self, xmlelement):
  297. Node.parseXML(self, xmlelement)
  298. for (at, av) in xmlelement.attributes.items():
  299. if at == "IsAbstract":
  300. self.isAbstract = "false" not in av.lower()
  301. class DataTypeNode(Node):
  302. """ DataTypeNode is a subtype of Node describing DataType nodes.
  303. DataType contain definitions and structure information usable for Variables.
  304. The format of this structure is determined by buildEncoding()
  305. Two definition styles are distinguished in XML:
  306. 1) A DataType can be a structure of fields, each field having a name and a type.
  307. The type must be either an encodable builtin node (ex. UInt32) or point to
  308. another DataType node that inherits its encoding from a builtin type using
  309. a inverse "hasSubtype" (hasSuperType) reference.
  310. 2) A DataType may be an enumeration, in which each field has a name and a numeric
  311. value.
  312. The definition is stored as an ordered list of tuples. Depending on which
  313. definition style was used, the __definition__ will hold
  314. 1) A list of ("Fieldname", Node) tuples.
  315. 2) A list of ("Fieldname", int) tuples.
  316. A DataType (and in consequence all Variables using it) shall be deemed not
  317. encodable if any of its fields cannot be traced to an encodable builtin type.
  318. A DataType shall be further deemed not encodable if it contains mixed structure/
  319. enumaration definitions.
  320. If encodable, the encoding can be retrieved using getEncoding().
  321. """
  322. def __init__(self, xmlelement=None):
  323. Node.__init__(self)
  324. self.isAbstract = False
  325. self.__xmlDefinition__ = None
  326. self.__baseTypeEncoding__ = []
  327. self.__encodable__ = None
  328. self.__definition__ = []
  329. self.__isEnum__ = False
  330. self.__isOptionSet__ = False
  331. if xmlelement:
  332. DataTypeNode.parseXML(self, xmlelement)
  333. def parseXML(self, xmlelement):
  334. Node.parseXML(self, xmlelement)
  335. for (at, av) in xmlelement.attributes.items():
  336. if at == "IsAbstract":
  337. self.isAbstract = "false" not in av.lower()
  338. for x in xmlelement.childNodes:
  339. if x.nodeType == x.ELEMENT_NODE:
  340. if x.localName == "Definition":
  341. self.__xmlDefinition__ = x
  342. def isEncodable(self):
  343. """ Will return True if buildEncoding() was able to determine which builtin
  344. type corresponds to all fields of this DataType.
  345. If no encoding has been build yet an exception will be thrown.
  346. Make sure to call buildEncoding() first.
  347. """
  348. if self.__encodable__ is None:
  349. raise Exception("Encoding needs to be built first using buildEncoding()")
  350. return self.__encodable__
  351. def getEncoding(self):
  352. """ If the dataType is encodable, getEncoding() returns a nested list
  353. containing the encoding the structure definition for this type.
  354. If no encoding has been build yet an exception will be thrown.
  355. Make sure to call buildEncoding() first.
  356. If buildEncoding() has failed, an empty list will be returned.
  357. """
  358. if self.__encodable__ is None:
  359. raise Exception("Encoding needs to be built first using buildEncoding()")
  360. if not self.__encodable__:
  361. return []
  362. else:
  363. return self.__baseTypeEncoding__
  364. def buildEncoding(self, nodeset, indent=0, force=False, namespaceMapping=None):
  365. """ buildEncoding() determines the structure and aliases used for variables
  366. of this DataType.
  367. The function will parse the XML <Definition> of the dataType and extract
  368. "Name"-"Type" tuples. If successful, buildEncoding will return a nested
  369. list of the following format:
  370. [['Alias1', ['Alias2', ['BuiltinType']]], [Alias2, ['BuiltinType']], ...]
  371. Aliases are fieldnames defined by this DataType or DataTypes referenced. A
  372. list such as ['DataPoint', ['Int32']] indicates that a value will encode
  373. an Int32 with the alias 'DataPoint' such as <DataPoint>12827</DataPoint>.
  374. Only the first Alias of a nested list is considered valid for the BuiltinType.
  375. Single-Elemented lists are always BuiltinTypes. Every nested list must
  376. converge in a builtin type to be encodable. buildEncoding will follow
  377. the first type inheritance reference (hasSupertype) of the dataType if
  378. necessary;
  379. If instead to "DataType" a numeric "Value" attribute is encountered,
  380. the DataType will be considered an enumeration and all Variables using
  381. it will be encoded as Int32.
  382. DataTypes can be either structures or enumeration - mixed definitions will
  383. be unencodable.
  384. Calls to getEncoding() will be iterative. buildEncoding() can be called
  385. only once per dataType, with all following calls returning the predetermined
  386. value. Use of the 'force=True' parameter will force the Definition to be
  387. reparsed.
  388. After parsing, __definition__ holds the field definition as a list. Note
  389. that this might deviate from the encoding, especially if inheritance was
  390. used.
  391. """
  392. prefix = " " + "|" * indent + "+"
  393. if force==True:
  394. self.__encodable__ = None
  395. if self.__encodable__ is not None and self.__encodable__:
  396. if self.isEncodable():
  397. logger.debug(prefix + str(self.__baseTypeEncoding__) + " (already analyzed)")
  398. else:
  399. logger.debug( prefix + str(self.__baseTypeEncoding__) + "(already analyzed, not encodable!)")
  400. return self.__baseTypeEncoding__
  401. self.__encodable__ = True
  402. if indent==0:
  403. logger.debug("Parsing DataType " + str(self.browseName) + " (" + str(self.id) + ")")
  404. if valueIsInternalType(self.browseName.name):
  405. self.__baseTypeEncoding__ = [self.browseName.name]
  406. self.__encodable__ = True
  407. logger.debug( prefix + str(self.browseName) + "*")
  408. logger.debug("Encodable as: " + str(self.__baseTypeEncoding__))
  409. logger.debug("")
  410. return self.__baseTypeEncoding__
  411. # Check if there is a supertype available
  412. parentType = None
  413. for ref in self.references:
  414. if ref.isForward:
  415. continue
  416. # hasSubtype
  417. if ref.referenceType.i == 45:
  418. targetNode = nodeset.nodes[ref.target]
  419. if targetNode is not None and isinstance(targetNode, DataTypeNode):
  420. parentType = targetNode
  421. break
  422. if self.__xmlDefinition__ is None:
  423. if parentType is not None:
  424. logger.debug( prefix + "Attempting definition using supertype " + str(targetNode.browseName) + " for DataType " + " " + str(self.browseName))
  425. subenc = targetNode.buildEncoding(nodeset=nodeset, indent=indent+1,
  426. namespaceMapping=namespaceMapping)
  427. if not targetNode.isEncodable():
  428. self.__encodable__ = False
  429. else:
  430. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
  431. if len(self.__baseTypeEncoding__) == 0:
  432. logger.debug(prefix + "No viable definition for " + str(self.browseName) + " " + str(self.id) + " found.")
  433. self.__encodable__ = False
  434. if indent==0:
  435. if not self.__encodable__:
  436. logger.debug("Not encodable (partial): " + str(self.__baseTypeEncoding__))
  437. else:
  438. logger.debug("Encodable as: " + str(self.__baseTypeEncoding__))
  439. logger.debug( "")
  440. return self.__baseTypeEncoding__
  441. isEnum = False
  442. # An option set is at the same time also an enum, at least for the encoding below
  443. isOptionSet = parentType is not None and parentType.id.ns == 0 and parentType.id.i==12755
  444. # We need to store the definition as ordered data, but can't use orderedDict
  445. # for backward compatibility with Python 2.6 and 3.4
  446. enumDict = []
  447. typeDict = []
  448. # An XML Definition is provided and will be parsed... now
  449. for x in self.__xmlDefinition__.childNodes:
  450. if x.nodeType == x.ELEMENT_NODE:
  451. fname = ""
  452. fdtype = ""
  453. enumVal = ""
  454. valueRank = None
  455. #symbolicName = None
  456. for at,av in x.attributes.items():
  457. if at == "DataType":
  458. fdtype = str(av)
  459. if fdtype in nodeset.aliases:
  460. fdtype = nodeset.aliases[fdtype]
  461. elif at == "Name":
  462. fname = str(av)
  463. elif at == "SymbolicName":
  464. # ignore
  465. continue
  466. # symbolicName = str(av)
  467. elif at == "Value":
  468. enumVal = int(av)
  469. isEnum = True
  470. elif at == "ValueRank":
  471. valueRank = int(av)
  472. else:
  473. logger.warn("Unknown Field Attribute " + str(at))
  474. # This can either be an enumeration OR a structure, not both.
  475. # Figure out which of the dictionaries gets the newly read value pair
  476. if isEnum:
  477. # This is an enumeration
  478. enumDict.append((fname, enumVal))
  479. continue
  480. else:
  481. if fdtype == "":
  482. # If no datatype given use base datatype
  483. fdtype = "i=24"
  484. # This might be a subtype... follow the node defined as datatype to find out
  485. # what encoding to use
  486. fdTypeNodeId = NodeId(fdtype)
  487. if namespaceMapping != None:
  488. fdTypeNodeId.ns = namespaceMapping[fdTypeNodeId.ns]
  489. if not fdTypeNodeId in nodeset.nodes:
  490. raise Exception("Node {} not found in nodeset".format(fdTypeNodeId))
  491. dtnode = nodeset.nodes[fdTypeNodeId]
  492. # The node in the datatype element was found. we inherit its encoding,
  493. # but must still ensure that the dtnode is itself validly encodable
  494. typeDict.append([fname, dtnode])
  495. fdtype = str(dtnode.browseName.name)
  496. logger.debug( prefix + fname + " : " + fdtype + " -> " + str(dtnode.id))
  497. subenc = dtnode.buildEncoding(nodeset=nodeset, indent=indent+1,
  498. namespaceMapping=namespaceMapping)
  499. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [[fname, subenc, valueRank]]
  500. if not dtnode.isEncodable():
  501. # If we inherit an encoding from an unencodable node, this node is
  502. # also not encodable
  503. self.__encodable__ = False
  504. break
  505. # If we used inheritance to determine an encoding without alias, there is a
  506. # the possibility that lists got double-nested despite of only one element
  507. # being encoded, such as [['Int32']] or [['alias',['int32']]]. Remove that
  508. # enclosing list.
  509. while len(self.__baseTypeEncoding__) == 1 and isinstance(self.__baseTypeEncoding__[0], list):
  510. self.__baseTypeEncoding__ = self.__baseTypeEncoding__[0]
  511. if isOptionSet == True:
  512. self.__isOptionSet__ = True
  513. subenc = parentType.buildEncoding(nodeset=nodeset, namespaceMapping=namespaceMapping)
  514. if not parentType.isEncodable():
  515. self.__encodable__ = False
  516. else:
  517. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
  518. self.__definition__ = enumDict
  519. return self.__baseTypeEncoding__
  520. if isEnum == True:
  521. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + ['Int32']
  522. self.__definition__ = enumDict
  523. self.__isEnum__ = True
  524. logger.debug( prefix+"Int32* -> enumeration with dictionary " + str(enumDict) + " encodable " + str(self.__encodable__))
  525. return self.__baseTypeEncoding__
  526. if indent==0:
  527. if not self.__encodable__:
  528. logger.debug( "Not encodable (partial): " + str(self.__baseTypeEncoding__))
  529. else:
  530. logger.debug( "Encodable as: " + str(self.__baseTypeEncoding__))
  531. self.__isEnum__ = False
  532. self.__definition__ = typeDict
  533. logger.debug( "")
  534. return self.__baseTypeEncoding__
  535. class ViewNode(Node):
  536. def __init__(self, xmlelement=None):
  537. Node.__init__(self)
  538. self.containsNoLoops = False
  539. self.eventNotifier = False
  540. if xmlelement:
  541. ViewNode.parseXML(self, xmlelement)
  542. def parseXML(self, xmlelement):
  543. Node.parseXML(self, xmlelement)
  544. for (at, av) in xmlelement.attributes.items():
  545. if at == "ContainsNoLoops":
  546. self.containsNoLoops = "false" not in av.lower()
  547. if at == "EventNotifier":
  548. self.eventNotifier = "false" not in av.lower()