Quellcode durchsuchen

NodesetCompiler: Correctly handle namespace mapping for encoded objects. Fixes #2137

Stefan Profanter vor 5 Jahren
Ursprung
Commit
e1b11ea2e7
2 geänderte Dateien mit 30 neuen und 7 gelöschten Zeilen
  1. 6 3
      tools/nodeset_compiler/nodes.py
  2. 24 4
      tools/nodeset_compiler/nodeset.py

+ 6 - 3
tools/nodeset_compiler/nodes.py

@@ -70,6 +70,7 @@ class Node(object):
         self.userWriteMask = 0
         self.references = set()
         self.hidden = False
+        self.modelUri = None
 
     def __str__(self):
         return self.__class__.__name__ + "(" + str(self.id) + ")"
@@ -560,9 +561,11 @@ class DataTypeNode(Node):
 
                     # This might be a subtype... follow the node defined as datatype to find out
                     # what encoding to use
-                    if not NodeId(fdtype) in nodeset.nodes:
-                        raise Exception("Node {} not found in nodeset".format(NodeId(fdtype)))
-                    dtnode = nodeset.nodes[NodeId(fdtype)]
+                    fdTypeNodeId = NodeId(fdtype)
+                    fdTypeNodeId.ns = nodeset.namespaceMapping[self.modelUri][fdTypeNodeId.ns]
+                    if not fdTypeNodeId in nodeset.nodes:
+                        raise Exception("Node {} not found in nodeset".format(fdTypeNodeId))
+                    dtnode = nodeset.nodes[fdTypeNodeId]
                     # The node in the datatype element was found. we inherit its encoding,
                     # but must still ensure that the dtnode is itself validly encodable
                     typeDict.append([fname, dtnode])

+ 24 - 4
tools/nodeset_compiler/nodeset.py

@@ -108,6 +108,7 @@ class NodeSet(object):
         self.nodes = {}
         self.aliases = {}
         self.namespaces = ["http://opcfoundation.org/UA/"]
+        self.namespaceMapping = {};
 
     def sanitize(self):
         for n in self.nodes.values():
@@ -148,7 +149,7 @@ class NodeSet(object):
     def getRoot(self):
         return self.getNodeByBrowseName("Root")
 
-    def createNode(self, xmlelement, nsMapping, hidden=False):
+    def createNode(self, xmlelement, modelUri, hidden=False):
         ndtype = xmlelement.localName.lower()
         if ndtype[:2] == "ua":
             ndtype = ndtype[2:]
@@ -174,6 +175,7 @@ class NodeSet(object):
         if node == None:
             return None
 
+        node.modelUri = modelUri
         node.hidden = hidden
         return node
 
@@ -212,11 +214,29 @@ class NodeSet(object):
             raise Exception(self, self.originXML + " contains no or more then 1 nodeset")
         nodeset = nodesets[0]
 
+
+        # Extract the modelUri
+        modelUri = None
+        try:
+            modelTag = nodeset.getElementsByTagName("Models")[0].getElementsByTagName("Model")[0]
+            modelUri = modelTag.attributes["ModelUri"].nodeValue
+        except:
+            # Ignore exception and try to use namespace array
+            modelUri = None
+
+
         # Create the namespace mapping
         orig_namespaces = extractNamespaces(xmlfile)  # List of namespaces used in the xml file
+        if modelUri is None and len(orig_namespaces) > 0:
+            modelUri = orig_namespaces[0]
+
+        if modelUri is None:
+            raise Exception(self, self.originXML + " does not define the nodeset URI in Models/Model/ModelUri or NamespaceUris array.")
+
+
         for ns in orig_namespaces:
             self.addNamespace(ns)
-        nsMapping = self.createNamespaceMapping(orig_namespaces)
+        self.namespaceMapping[modelUri] = self.createNamespaceMapping(orig_namespaces)
 
         # Extract the aliases
         for nd in nodeset.childNodes:
@@ -231,11 +251,11 @@ class NodeSet(object):
         for nd in nodeset.childNodes:
             if nd.nodeType != nd.ELEMENT_NODE:
                 continue
-            node = self.createNode(nd, nsMapping, hidden)
+            node = self.createNode(nd, modelUri, hidden)
             if not node:
                 continue
             node.replaceAliases(self.aliases)
-            node.replaceNamespaces(nsMapping)
+            node.replaceNamespaces(self.namespaceMapping[modelUri])
             node.typesArray = typesArray
 
             # Add the node the the global dict