nodes.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. for x in xmlelement.childNodes:
  223. if x.nodeType != x.ELEMENT_NODE:
  224. continue
  225. if x.localName == "Value":
  226. self.xmlValueDef = x
  227. elif x.localName == "DataType":
  228. self.dataType = RefOrAlias(av)
  229. elif x.localName == "ValueRank":
  230. self.valueRank = int(unicode(x.firstChild.data))
  231. elif x.localName == "ArrayDimensions" and len(self.arrayDimensions) == 0:
  232. elements = x.getElementsByTagName("ListOfUInt32");
  233. if len(elements):
  234. for idx, v in enumerate(elements[0].getElementsByTagName("UInt32")):
  235. self.arrayDimensions.append(v.firstChild.data)
  236. elif x.localName == "AccessLevel":
  237. self.accessLevel = int(unicode(x.firstChild.data))
  238. elif x.localName == "UserAccessLevel":
  239. self.userAccessLevel = int(unicode(x.firstChild.data))
  240. elif x.localName == "MinimumSamplingInterval":
  241. self.minimumSamplingInterval = float(unicode(x.firstChild.data))
  242. elif x.localName == "Historizing":
  243. self.historizing = "false" not in x.lower()
  244. def allocateValue(self, nodeset):
  245. dataTypeNode = nodeset.getDataTypeNode(self.dataType)
  246. if dataTypeNode is None:
  247. return False
  248. # FIXME: Don't build at all or allocate "defaults"? I'm for not building at all.
  249. if self.xmlValueDef is None:
  250. #logger.warn("Variable " + self.browseName() + "/" + str(self.id()) + " is not initialized. No memory will be allocated.")
  251. return False
  252. self.value = Value()
  253. self.value.parseXMLEncoding(self.xmlValueDef, dataTypeNode, self)
  254. return True
  255. class VariableTypeNode(VariableNode):
  256. def __init__(self, xmlelement=None):
  257. VariableNode.__init__(self)
  258. self.isAbstract = False
  259. if xmlelement:
  260. VariableTypeNode.parseXML(self, xmlelement)
  261. def parseXML(self, xmlelement):
  262. VariableNode.parseXML(self, xmlelement)
  263. for (at, av) in xmlelement.attributes.items():
  264. if at == "IsAbstract":
  265. self.isAbstract = "false" not in av.lower()
  266. for x in xmlelement.childNodes:
  267. if x.nodeType != x.ELEMENT_NODE:
  268. continue
  269. if x.localName == "IsAbstract":
  270. self.isAbstract = "false" not in av.lower()
  271. class MethodNode(Node):
  272. def __init__(self, xmlelement=None):
  273. Node.__init__(self)
  274. self.executable = True
  275. self.userExecutable = True
  276. self.methodDecalaration = None
  277. if xmlelement:
  278. MethodNode.parseXML(self, xmlelement)
  279. def parseXML(self, xmlelement):
  280. Node.parseXML(self, xmlelement)
  281. for (at, av) in xmlelement.attributes.items():
  282. if at == "Executable":
  283. self.executable = "false" not in av.lower()
  284. if at == "UserExecutable":
  285. self.userExecutable = "false" not in av.lower()
  286. if at == "MethodDeclarationId":
  287. self.methodDeclaration = str(av)
  288. class ObjectTypeNode(Node):
  289. def __init__(self, xmlelement=None):
  290. Node.__init__(self)
  291. self.isAbstract = False
  292. if xmlelement:
  293. ObjectTypeNode.parseXML(self, xmlelement)
  294. def parseXML(self, xmlelement):
  295. Node.parseXML(self, xmlelement)
  296. for (at, av) in xmlelement.attributes.items():
  297. if at == "IsAbstract":
  298. self.isAbstract = "false" not in av.lower()
  299. class DataTypeNode(Node):
  300. """ DataTypeNode is a subtype of Node describing DataType nodes.
  301. DataType contain definitions and structure information usable for Variables.
  302. The format of this structure is determined by buildEncoding()
  303. Two definition styles are distinguished in XML:
  304. 1) A DataType can be a structure of fields, each field having a name and a type.
  305. The type must be either an encodable builtin node (ex. UInt32) or point to
  306. another DataType node that inherits its encoding from a builtin type using
  307. a inverse "hasSubtype" (hasSuperType) reference.
  308. 2) A DataType may be an enumeration, in which each field has a name and a numeric
  309. value.
  310. The definition is stored as an ordered list of tuples. Depending on which
  311. definition style was used, the __definition__ will hold
  312. 1) A list of ("Fieldname", Node) tuples.
  313. 2) A list of ("Fieldname", int) tuples.
  314. A DataType (and in consequence all Variables using it) shall be deemed not
  315. encodable if any of its fields cannot be traced to an encodable builtin type.
  316. A DataType shall be further deemed not encodable if it contains mixed structure/
  317. enumaration definitions.
  318. If encodable, the encoding can be retrieved using getEncoding().
  319. """
  320. def __init__(self, xmlelement=None):
  321. Node.__init__(self)
  322. self.isAbstract = False
  323. self.__xmlDefinition__ = None
  324. self.__baseTypeEncoding__ = []
  325. self.__encodable__ = None
  326. self.__definition__ = []
  327. self.__isEnum__ = False
  328. self.__isOptionSet__ = False
  329. if xmlelement:
  330. DataTypeNode.parseXML(self, xmlelement)
  331. def parseXML(self, xmlelement):
  332. Node.parseXML(self, xmlelement)
  333. for (at, av) in xmlelement.attributes.items():
  334. if at == "IsAbstract":
  335. self.isAbstract = "false" not in av.lower()
  336. for x in xmlelement.childNodes:
  337. if x.nodeType == x.ELEMENT_NODE:
  338. if x.localName == "Definition":
  339. self.__xmlDefinition__ = x
  340. def isEncodable(self):
  341. """ Will return True if buildEncoding() was able to determine which builtin
  342. type corresponds to all fields of this DataType.
  343. If no encoding has been build yet an exception will be thrown.
  344. Make sure to call buildEncoding() first.
  345. """
  346. if self.__encodable__ is None:
  347. raise Exception("Encoding needs to be built first using buildEncoding()")
  348. return self.__encodable__
  349. def getEncoding(self):
  350. """ If the dataType is encodable, getEncoding() returns a nested list
  351. containing the encoding the structure definition for this type.
  352. If no encoding has been build yet an exception will be thrown.
  353. Make sure to call buildEncoding() first.
  354. If buildEncoding() has failed, an empty list will be returned.
  355. """
  356. if self.__encodable__ is None:
  357. raise Exception("Encoding needs to be built first using buildEncoding()")
  358. if not self.__encodable__:
  359. return []
  360. else:
  361. return self.__baseTypeEncoding__
  362. def buildEncoding(self, nodeset, indent=0, force=False, namespaceMapping=None):
  363. """ buildEncoding() determines the structure and aliases used for variables
  364. of this DataType.
  365. The function will parse the XML <Definition> of the dataType and extract
  366. "Name"-"Type" tuples. If successful, buildEncoding will return a nested
  367. list of the following format:
  368. [['Alias1', ['Alias2', ['BuiltinType']]], [Alias2, ['BuiltinType']], ...]
  369. Aliases are fieldnames defined by this DataType or DataTypes referenced. A
  370. list such as ['DataPoint', ['Int32']] indicates that a value will encode
  371. an Int32 with the alias 'DataPoint' such as <DataPoint>12827</DataPoint>.
  372. Only the first Alias of a nested list is considered valid for the BuiltinType.
  373. Single-Elemented lists are always BuiltinTypes. Every nested list must
  374. converge in a builtin type to be encodable. buildEncoding will follow
  375. the first type inheritance reference (hasSupertype) of the dataType if
  376. necessary;
  377. If instead to "DataType" a numeric "Value" attribute is encountered,
  378. the DataType will be considered an enumeration and all Variables using
  379. it will be encoded as Int32.
  380. DataTypes can be either structures or enumeration - mixed definitions will
  381. be unencodable.
  382. Calls to getEncoding() will be iterative. buildEncoding() can be called
  383. only once per dataType, with all following calls returning the predetermined
  384. value. Use of the 'force=True' parameter will force the Definition to be
  385. reparsed.
  386. After parsing, __definition__ holds the field definition as a list. Note
  387. that this might deviate from the encoding, especially if inheritance was
  388. used.
  389. """
  390. prefix = " " + "|" * indent + "+"
  391. if force==True:
  392. self.__encodable__ = None
  393. if self.__encodable__ is not None and self.__encodable__:
  394. if self.isEncodable():
  395. logger.debug(prefix + str(self.__baseTypeEncoding__) + " (already analyzed)")
  396. else:
  397. logger.debug( prefix + str(self.__baseTypeEncoding__) + "(already analyzed, not encodable!)")
  398. return self.__baseTypeEncoding__
  399. self.__encodable__ = True
  400. if indent==0:
  401. logger.debug("Parsing DataType " + str(self.browseName) + " (" + str(self.id) + ")")
  402. if valueIsInternalType(self.browseName.name):
  403. self.__baseTypeEncoding__ = [self.browseName.name]
  404. self.__encodable__ = True
  405. logger.debug( prefix + str(self.browseName) + "*")
  406. logger.debug("Encodable as: " + str(self.__baseTypeEncoding__))
  407. logger.debug("")
  408. return self.__baseTypeEncoding__
  409. # Check if there is a supertype available
  410. parentType = None
  411. for ref in self.references:
  412. if ref.isForward:
  413. continue
  414. # hasSubtype
  415. if ref.referenceType.i == 45:
  416. targetNode = nodeset.nodes[ref.target]
  417. if targetNode is not None and isinstance(targetNode, DataTypeNode):
  418. parentType = targetNode
  419. break
  420. if self.__xmlDefinition__ is None:
  421. if parentType is not None:
  422. logger.debug( prefix + "Attempting definition using supertype " + str(targetNode.browseName) + " for DataType " + " " + str(self.browseName))
  423. subenc = targetNode.buildEncoding(nodeset=nodeset, indent=indent+1,
  424. namespaceMapping=namespaceMapping)
  425. if not targetNode.isEncodable():
  426. self.__encodable__ = False
  427. else:
  428. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
  429. if len(self.__baseTypeEncoding__) == 0:
  430. logger.debug(prefix + "No viable definition for " + str(self.browseName) + " " + str(self.id) + " found.")
  431. self.__encodable__ = False
  432. if indent==0:
  433. if not self.__encodable__:
  434. logger.debug("Not encodable (partial): " + str(self.__baseTypeEncoding__))
  435. else:
  436. logger.debug("Encodable as: " + str(self.__baseTypeEncoding__))
  437. logger.debug( "")
  438. return self.__baseTypeEncoding__
  439. isEnum = False
  440. # An option set is at the same time also an enum, at least for the encoding below
  441. isOptionSet = parentType is not None and parentType.id.ns == 0 and parentType.id.i==12755
  442. # We need to store the definition as ordered data, but can't use orderedDict
  443. # for backward compatibility with Python 2.6 and 3.4
  444. enumDict = []
  445. typeDict = []
  446. # An XML Definition is provided and will be parsed... now
  447. for x in self.__xmlDefinition__.childNodes:
  448. if x.nodeType == x.ELEMENT_NODE:
  449. fname = ""
  450. fdtype = ""
  451. enumVal = ""
  452. valueRank = None
  453. #symbolicName = None
  454. for at,av in x.attributes.items():
  455. if at == "DataType":
  456. fdtype = str(av)
  457. if fdtype in nodeset.aliases:
  458. fdtype = nodeset.aliases[fdtype]
  459. elif at == "Name":
  460. fname = str(av)
  461. elif at == "SymbolicName":
  462. # ignore
  463. continue
  464. # symbolicName = str(av)
  465. elif at == "Value":
  466. enumVal = int(av)
  467. isEnum = True
  468. elif at == "ValueRank":
  469. valueRank = int(av)
  470. else:
  471. logger.warn("Unknown Field Attribute " + str(at))
  472. # This can either be an enumeration OR a structure, not both.
  473. # Figure out which of the dictionaries gets the newly read value pair
  474. if isEnum:
  475. # This is an enumeration
  476. enumDict.append((fname, enumVal))
  477. continue
  478. else:
  479. if fdtype == "":
  480. # If no datatype given use base datatype
  481. fdtype = "i=24"
  482. # This might be a subtype... follow the node defined as datatype to find out
  483. # what encoding to use
  484. fdTypeNodeId = NodeId(fdtype)
  485. if namespaceMapping != None:
  486. fdTypeNodeId.ns = namespaceMapping[fdTypeNodeId.ns]
  487. if not fdTypeNodeId in nodeset.nodes:
  488. raise Exception("Node {} not found in nodeset".format(fdTypeNodeId))
  489. dtnode = nodeset.nodes[fdTypeNodeId]
  490. # The node in the datatype element was found. we inherit its encoding,
  491. # but must still ensure that the dtnode is itself validly encodable
  492. typeDict.append([fname, dtnode])
  493. fdtype = str(dtnode.browseName.name)
  494. logger.debug( prefix + fname + " : " + fdtype + " -> " + str(dtnode.id))
  495. subenc = dtnode.buildEncoding(nodeset=nodeset, indent=indent+1,
  496. namespaceMapping=namespaceMapping)
  497. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [[fname, subenc, valueRank]]
  498. if not dtnode.isEncodable():
  499. # If we inherit an encoding from an unencodable node, this node is
  500. # also not encodable
  501. self.__encodable__ = False
  502. break
  503. # If we used inheritance to determine an encoding without alias, there is a
  504. # the possibility that lists got double-nested despite of only one element
  505. # being encoded, such as [['Int32']] or [['alias',['int32']]]. Remove that
  506. # enclosing list.
  507. while len(self.__baseTypeEncoding__) == 1 and isinstance(self.__baseTypeEncoding__[0], list):
  508. self.__baseTypeEncoding__ = self.__baseTypeEncoding__[0]
  509. if isOptionSet == True:
  510. self.__isOptionSet__ = True
  511. subenc = parentType.buildEncoding(nodeset=nodeset, namespaceMapping=namespaceMapping)
  512. if not parentType.isEncodable():
  513. self.__encodable__ = False
  514. else:
  515. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName.name, subenc, None]
  516. self.__definition__ = enumDict
  517. return self.__baseTypeEncoding__
  518. if isEnum == True:
  519. self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + ['Int32']
  520. self.__definition__ = enumDict
  521. self.__isEnum__ = True
  522. logger.debug( prefix+"Int32* -> enumeration with dictionary " + str(enumDict) + " encodable " + str(self.__encodable__))
  523. return self.__baseTypeEncoding__
  524. if indent==0:
  525. if not self.__encodable__:
  526. logger.debug( "Not encodable (partial): " + str(self.__baseTypeEncoding__))
  527. else:
  528. logger.debug( "Encodable as: " + str(self.__baseTypeEncoding__))
  529. self.__isEnum__ = False
  530. self.__definition__ = typeDict
  531. logger.debug( "")
  532. return self.__baseTypeEncoding__
  533. class ViewNode(Node):
  534. def __init__(self, xmlelement=None):
  535. Node.__init__(self)
  536. self.containsNoLoops = False
  537. self.eventNotifier = False
  538. if xmlelement:
  539. ViewNode.parseXML(self, xmlelement)
  540. def parseXML(self, xmlelement):
  541. Node.parseXML(self, xmlelement)
  542. for (at, av) in xmlelement.attributes.items():
  543. if at == "ContainsNoLoops":
  544. self.containsNoLoops = "false" not in av.lower()
  545. if at == "EventNotifier":
  546. self.eventNotifier = "false" not in av.lower()