Преглед изворни кода

added utility functions to traverse namespace

Leon Urbas пре 10 година
родитељ
комит
a1589bd00f
5 измењених фајлова са 221 додато и 39 уклоњено
  1. 93 22
      examples/src/generateSam.c
  2. 1 0
      include/ua_basictypes.h
  3. 125 12
      src/ua_xml.c
  4. 1 1
      src/ua_xml.h
  5. 1 4
      tools/generate_builtin.py

+ 93 - 22
examples/src/generateSam.c

@@ -11,47 +11,118 @@
 /** @brief we need a variable global to the module to make it possible for the visitors to access the namespace */
 static Namespace* theNamespace;
 
-/** @brief check if VariableNode is root by searching for parent and checking if this is not a VariableNode */
-_Bool UA_VariableNode_isRoot(const UA_VariableNode* node) {
-	UA_Int32 i;
-	for (i = 0; i < node->referencesSize; i++ ) {
+UA_Int32 UA_Node_getParent(const UA_Node* node, const UA_Node** parent) {
+	UA_Int32 i = 0;
+	DBG_VERBOSE(printf("// UA_Node_getParent - node={i=%d}",UA_NodeId_getIdentifier(&(node->nodeId))));
+	for (; i < node->referencesSize; i++ ) {
 		UA_Int32 refId = UA_NodeId_getIdentifier(&(node->references[i]->referenceTypeId));
 		UA_Int32 isInverse = node->references[i]->isInverse;
 		if (isInverse && (refId == 47 || refId == 46)) {
-			Namespace_Entry_Lock* lock;
-			const UA_Node* parent;
+			Namespace_Entry_Lock* lock = UA_NULL;
 			UA_Int32 retval;
-			retval = Namespace_get(theNamespace, &(node->references[i]->targetId.nodeId),&parent,&lock);
-			if (retval != UA_SUCCESS || parent == UA_NULL || parent->nodeClass == UA_NODECLASS_VARIABLE) {
-				if (node->nodeId.identifier.numeric == 2007) {
-					printf("strange 2007 not included retval=%d,parentId=%d,parent=%p\n, ",retval,node->references[i]->targetId.nodeId.identifier.numeric,(void*)parent);
-				}
-				Namespace_Entry_Lock_release(lock);
-				return UA_FALSE;
-			}
+			retval = Namespace_get(theNamespace, &(node->references[i]->targetId.nodeId),parent,&lock);
 			Namespace_Entry_Lock_release(lock);
+			if (retval == UA_SUCCESS) {
+				DBG_VERBOSE(printf(" has parent={i=%d}\n",UA_NodeId_getIdentifier(&((*parent)->nodeId))));
+			} else {
+				DBG_VERBOSE(printf(" has non-existing parent={i=%d}\n",UA_NodeId_getIdentifier(&(node->references[i]->targetId.nodeId))));
+			}
+			return retval;
 		}
 	}
-	return UA_TRUE;
+	// there is no parent, we are root
+	DBG_VERBOSE(printf(" is root\n"));
+	*parent = UA_NULL;
+	return UA_SUCCESS;
 }
 
+/** @brief recurse down to root and return root node */
+UA_Int32 UA_Node_getRoot(const UA_Node* node, const UA_Node** root) {
+	UA_Int32 retval = UA_SUCCESS;
+	const UA_Node* parent = UA_NULL;
+	if ( (retval = UA_Node_getParent(node,&parent)) == UA_SUCCESS ) {
+		if (parent != UA_NULL) {	// recurse down to root node
+			retval = UA_Node_getRoot(parent,root);
+		} else {					// node is root, terminate recursion
+			*root = node;
+		}
+	}
+	return retval;
+}
+
+/** @brief check if VariableNode needs a memory object. This is the
+ * case if the parent is of type object and the root is type object
+ **/
+_Bool UA_VariableNode_needsObject(const UA_VariableNode* node) {
+	const UA_Node* parent = UA_NULL;
+	if ( UA_Node_getParent((UA_Node*)node,&parent) == UA_SUCCESS ) {
+		if (parent == UA_NULL)
+			return UA_TRUE;
+		if (parent->nodeClass == UA_NODECLASS_OBJECT ) {
+			const UA_Node* root;
+			if (UA_Node_getRoot(parent,&root) == UA_SUCCESS)
+				if (root == UA_NULL || root->nodeClass == UA_NODECLASS_OBJECT )
+					return UA_TRUE;
+		}
+	}
+	return UA_FALSE;
+}
+
+/** @brief recurse down to root and get full qualified name */
+UA_Int32 UA_Node_getPath(const UA_Node* node, UA_list_List* list) {
+	UA_Int32 retval = UA_SUCCESS;
+	const UA_Node* parent = UA_NULL;
+	if ( (retval = UA_Node_getParent(node,&parent)) == UA_SUCCESS ) {
+		if (parent != UA_NULL) {
+			// recurse down to root node
+			UA_Int32 retval = UA_Node_getPath(parent,list);
+			// and add our own name when we come back
+			if (retval == UA_SUCCESS) {
+				UA_list_addPayloadToBack(list,(void*)&(node->browseName.name));
+				printf("// UA_Node_getPath - add id={i=%d},class=%d",UA_NodeId_getIdentifier(&(node->nodeId)),node->nodeClass);
+				UA_String_printf(",name=",&(node->browseName.name));
+			}
+		} else {
+			// node is root, terminate recursion by adding own name
+			UA_list_addPayloadToBack(list,(void*)&node->browseName.name);
+			printf("// UA_Node_getPath - add id={i=%d},class=%d",UA_NodeId_getIdentifier(&(node->nodeId)),node->nodeClass);
+			UA_String_printf(",name=",&(node->browseName.name));
+		}
+	}
+	return retval;
+}
+
+
 /** @brief some macros to lowercase the first character without copying around */
 #define F_cls "%c%.*s"
 #define LC_cls(str) tolower((str).data[0]), (str).length-1, &((str).data[1])
 
+void listPrintName(void * payload) {
+	UA_ByteString* name = (UA_ByteString*) payload;
+	if (name->length > 0) {
+		printf("_" F_cls, LC_cls(*name));
+	}
+}
 
-/** @brief declares all the top level objects in the server's application memory
- * FIXME: shall add only top level objects, i.e. those that have no parents
- */
+/** @brief declares all the top level objects in the server's application memory */
 void sam_declareAttribute(UA_Node const * node) {
-	if (node->nodeClass == UA_NODECLASS_VARIABLE && UA_VariableNode_isRoot((UA_VariableNode*)node)) {
-		UA_VariableNode* vn = (UA_VariableNode*) node;
-		printf("\t%s " F_cls "; // i=%d\n", UA_[UA_ns0ToVTableIndex(vn->dataType.identifier.numeric)].name, LC_cls(node->browseName.name), node->nodeId.identifier.numeric);
+	if (node->nodeClass == UA_NODECLASS_VARIABLE && UA_VariableNode_needsObject((UA_VariableNode*)node)) {
+		UA_list_List list; UA_list_init(&list);
+		UA_Int32 retval = UA_Node_getPath(node,&list);
+		if (retval == UA_SUCCESS) {
+			UA_VariableNode* vn = (UA_VariableNode*) node;
+			printf("\t%s ", UA_[UA_ns0ToVTableIndex(vn->dataType.identifier.numeric)].name);
+			UA_list_iteratePayload(&list,listPrintName);
+			printf("; // i=%d\n", node->nodeId.identifier.numeric);
+		} else {
+			printf("// could not determine path for i=%d\n",node->nodeId.identifier.numeric);
+		}
+		UA_list_destroy(&list,UA_NULL);
 	}
 }
 
 /** @brief declares all the buffers for string variables
- * FIXME: traverse down to top level objects and create a unique name such as cstr_serverState_buildInfo_version
+ * FIXME: shall traverse down to the root object and create a unique name such as cstr_serverState_buildInfo_version
  */
 void sam_declareBuffer(UA_Node const * node) {
 	if (node != UA_NULL && node->nodeClass == UA_NODECLASS_VARIABLE) {

+ 1 - 0
include/ua_basictypes.h

@@ -394,6 +394,7 @@ typedef struct XML_Parent {
 typedef struct XML_Stack {
 	int depth;
 	XML_Parent parent[XML_STACK_MAX_DEPTH];
+	UA_Int32 nsid;
 	UA_NodeSetAliases* aliases; // shall point to the aliases of the NodeSet after reading
 } XML_Stack;
 

+ 125 - 12
src/ua_xml.c

@@ -118,7 +118,7 @@ UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_N
 	return UA_SUCCESS;
 }
 
-void XML_Stack_init(XML_Stack* p, cstring name) {
+void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name) {
 	unsigned int i, j;
 	p->depth = 0;
 	for (i = 0; i < XML_STACK_MAX_DEPTH; i++) {
@@ -135,6 +135,7 @@ void XML_Stack_init(XML_Stack* p, cstring name) {
 			p->parent[i].children[j].obj = UA_NULL;
 		}
 	}
+	p->nsid = nsid;
 	p->parent[0].name = name;
 }
 
@@ -474,7 +475,6 @@ UA_Int32 UA_TypedArray_decodeXML(XML_Stack* s, XML_Attr* attr, UA_TypedArray* ds
 	return UA_SUCCESS;
 }
 
-
 UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_DataTypeNode* dst, _Bool isStart) {
 	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
 	UA_UInt32 i;
@@ -531,6 +531,118 @@ UA_Int32 UA_DataTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_DataTypeNode
 	return UA_SUCCESS;
 }
 
+UA_Int32 UA_ObjectTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectTypeNode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_ObjectTypeNode_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
+		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
+		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->description));
+		XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->description));
+		XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
+
+		// set missing default attributes
+		dst->nodeClass = UA_NODECLASS_OBJECTTYPE;
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
+			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
+				dst->browseName.namespaceIndex = 0;
+			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) {
+				UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->description.text));
+				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else {
+				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	} else {
+		switch (s->parent[s->depth - 1].activeChild) {
+		case 4: // References
+			if (attr != UA_NULL) {
+				UA_TypedArray* array = (UA_TypedArray *) attr;
+				DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+				dst->referencesSize = array->size;
+				dst->references = (UA_ReferenceNode**) array->elements;
+			}
+		break;
+		}
+	}
+	return UA_SUCCESS;
+}
+
+UA_Int32 UA_VariableTypeNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_VariableTypeNode* dst, _Bool isStart) {
+	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
+	UA_UInt32 i;
+
+	if (isStart) {
+		// create a new object if called with UA_NULL
+		if (dst == UA_NULL) {
+			UA_VariableTypeNode_new(&dst);
+			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
+		}
+
+		s->parent[s->depth].len = 0;
+		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
+		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
+		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->description));
+		XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXML, UA_BOOLEAN, &(dst->description));
+		XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
+
+		// set missing default attributes
+		dst->nodeClass = UA_NODECLASS_VARIABLETYPE;
+
+		// set attributes
+		for (i = 0; attr[i]; i += 2) {
+			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
+				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
+			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
+				dst->browseName.namespaceIndex = 0;
+			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->displayName.text));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) {
+				UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract));
+				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->description.text));
+				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+			} else {
+				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
+			}
+		}
+	} else {
+		switch (s->parent[s->depth - 1].activeChild) {
+		case 4: // References
+			if (attr != UA_NULL) {
+				UA_TypedArray* array = (UA_TypedArray *) attr;
+				DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
+				dst->referencesSize = array->size;
+				dst->references = (UA_ReferenceNode**) array->elements;
+			}
+		break;
+		}
+	}
+	return UA_SUCCESS;
+}
+
 UA_Int32 UA_ObjectNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectNode* dst, _Bool isStart) {
 	DBG_VERBOSE(printf("UA_ObjectNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
 	UA_UInt32 i;
@@ -542,22 +654,23 @@ UA_Int32 UA_ObjectNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectNode* ds
 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
 		}
 
-		// s->parent[s->depth].len = 0;
 		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->displayName));
 		XML_Stack_addChildHandler(s, "Description", strlen("Description"), (XML_decoder) UA_LocalizedText_decodeXML, UA_LOCALIZEDTEXT, &(dst->description));
-		// FIXME: no idea how to handle SymbolicName automatically. Seems to me that it is the "real" BrowseName
-		//		XML_Stack_addChildHandler(s, "BrowseName", (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME,&(dst->browseName));
+		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"), (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME, &(dst->browseName));
 		XML_Stack_addChildHandler(s, "SymbolicName", strlen("SymbolicName"), (XML_decoder) UA_QualifiedName_decodeXML, UA_QUALIFIEDNAME,&(dst->browseName));
 		XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXML, UA_REFERENCENODE, UA_NULL);
 
 		// set missing default attributes
-		dst->nodeClass = UA_NODECLASS_DATATYPE;
+		dst->nodeClass = UA_NODECLASS_OBJECT;
 
 		// set attributes
 		for (i = 0; attr[i]; i += 2) {
 			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) {
 				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases);
-			} else if (0 == strncmp("SymbolicName", attr[i], strlen("SymboliName"))) {
+			} else if (0 == strncmp("SymbolicName", attr[i], strlen("SymbolicName"))) {
+				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
+				dst->browseName.namespaceIndex = 0;
+			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) {
 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name));
 				dst->browseName.namespaceIndex = 0;
 			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) {
@@ -571,7 +684,7 @@ UA_Int32 UA_ObjectNode_decodeXML(XML_Stack* s, XML_Attr* attr, UA_ObjectNode* ds
 			}
 		}
 	} else {
-		if (s->parent[s->depth - 1].activeChild == 3 && attr != UA_NULL ) { // References Array
+		if (s->parent[s->depth - 1].activeChild == 4 && attr != UA_NULL ) { // References Array
 			UA_TypedArray* array = (UA_TypedArray*) attr;
 			DBG(printf("UA_ObjectNode_decodeXML finished references: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size));
 			dst->referencesSize = array->size;
@@ -865,7 +978,7 @@ UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bo
 	DBG_VERBOSE(printf("UA_NodeSet entered with dst=%p,isStart=%d\n", (void* ) dst, isStart));
 	if (isStart) {
 		if (dst == UA_NULL) {
-			UA_NodeSet_new(&dst, 99); // we don't really need the namespaceid for this..'
+			UA_NodeSet_new(&dst, s->nsid);
 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst;
 		}
 		s->parent[s->depth].len = 0;
@@ -882,7 +995,7 @@ UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bo
 			DBG(printf("UA_NodeSet_decodeXML - finished aliases: aliases=%p, size=%d\n",(void*)aliases,(aliases==UA_NULL)?-1:aliases->size));
 			s->aliases = aliases;
 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-		} else if (attr != UA_NULL && (s->parent[s->depth - 1].activeChild == 3 ||  s->parent[s->depth - 1].activeChild == 5)) {
+		} else {
 			UA_Node* node = (UA_Node*) attr;
 			DBG(printf("UA_NodeSet_decodeXML - finished node: node=%p\n", (void* )node));
 			Namespace_insert(dst->ns, node);
@@ -994,7 +1107,7 @@ void XML_Stack_endElement(void *data, const char *el) {
 	s->depth--;
 }
 
-UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 namespaceId,const char* rootName,const char* fileName) {
+UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* fileName) {
 	int f;
 	if (fileName == UA_NULL)
 		f = 0; // stdin
@@ -1005,7 +1118,7 @@ UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 namespaceId,const char*
 	int len; /* len is the number of bytes in the current bufferful of data */
 
 	XML_Stack s;
-	XML_Stack_init(&s, rootName);
+	XML_Stack_init(&s, nsid, rootName);
 
 	UA_NodeSet n;
 	UA_NodeSet_init(&n, 0);

+ 1 - 1
src/ua_xml.h

@@ -61,7 +61,7 @@ UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bo
 
 UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases);
 
-void XML_Stack_init(XML_Stack* p, cstring name);
+void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name);
 void XML_Stack_print(XML_Stack* s);
 
 /** @brief add a reference to a handler (@see XML_Stack_addChildHandler) for text data

+ 1 - 4
tools/generate_builtin.py

@@ -19,14 +19,11 @@ exclude_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UI
 					 "Variant", "DiagnosticInfo", "IntegerId"])
 
 # do not forget to get rid of these excludes once it works
-exclude_xml_decode = set(["UA_ReferenceNode", "UA_ObjectNode", "UA_VariableNode", "UA_DataTypeNode"])
+exclude_xml_decode = set(["UA_ReferenceNode", "UA_ObjectNode", "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_DataTypeNode"])
 
 elementary_size = {"Boolean":1, "SByte":1, "Byte":1, "Int16":2, "UInt16":2, "Int32":4, "UInt32":4,
                    "Int64":8, "UInt64":8, "Float":4, "Double":8, "DateTime":8, "StatusCode":4}
 
-# do not forget to get rid of these excludes once it works
-exclude_xml_decode = set(["UA_ReferenceNode", "UA_ObjectNode", "UA_VariableNode", "UA_DataTypeNode"])
-
 enum_types = []
 structured_types = []
 printed_types = exclude_types # types that were already printed and which we can use in the structures to come