public void loadXml(Node node) throws Exception {
		int nodeType = node.getNodeType();

		switch (nodeType) {
		case Node.DOCUMENT_NODE:
			loadXml(((Document) node).getDocumentElement());
			break;

		// print element with attributes
		case Node.ELEMENT_NODE:
			NamedNodeMap attrs = node.getAttributes();
			String tag = node.getNodeName();

			if (tag == "cluster") {
				// This is a device definition or extension
				int id = Converter.parseInteger(attrs.getNamedItem("id").getNodeValue());
				String name = attrs.getNamedItem("name").getNodeValue();
				name = transformName(name);

				if (clusters != null && clusters.size() != 0 && !clusters.contains(name))
					return;

				String status = "d";
				String packageName = null;

				if (attrs.getNamedItem("package") != null)
					packageName = attrs.getNamedItem("package").getNodeValue();

				if (attrs.getNamedItem("status") != null)
					status = attrs.getNamedItem("status").getNodeValue();

				if (status.equals("u")) {
					System.out.println("skipping still unimplemented cluster '" + name + "'");
					return;
				}

				zclClusterDescriptor = new ZclClusterDescriptor(name, id, packageName);
				zclClusters.add(zclClusterDescriptor);
			} else if (tag == "attribute") {
				// This is a cluster attribute definition

				int id = Converter.parseInteger(attrs.getNamedItem("id").getNodeValue());
				String name = attrs.getNamedItem("name").getNodeValue();
				String type = attrs.getNamedItem("type").getNodeValue();
				Node accessItem = attrs.getNamedItem("access");
				Node defItem = attrs.getNamedItem("default");
				Node mandatoryItem = attrs.getNamedItem("mandatory");
				Node reportableItem = attrs.getNamedItem("reportable");
				Node sizeItem = attrs.getNamedItem("size");

				int size = 0;

				boolean reportable = true;

				name = transformName(name);

				String uom = "";
				double factor = 1.0;

				try {
					uom = attrs.getNamedItem("uom").getNodeValue();
				} catch (Exception e) {
				}

				try {
					String sFactor = attrs.getNamedItem("factor").getNodeValue();
					factor = Double.parseDouble(sFactor);
				} catch (NullPointerException e) {
					// pass here when the factory attribute is not present
				}

				// default values
				boolean mandatory = true;
				String access = "r";
				String defValue = "";

				if (accessItem != null) {
					access = accessItem.getNodeValue();
				}

				if (mandatoryItem != null) {
					mandatory = Converter.parseBoolean(mandatoryItem.getNodeValue());
				}

				if (reportableItem != null) {
					reportable = Converter.parseBoolean(reportableItem.getNodeValue());
				}

				if (defItem != null) {
					defValue = defItem.getNodeValue();
				}

				if (sizeItem != null) {
					try {
						size = Integer.parseInt(sizeItem.getNodeValue());
					} catch (Exception e) {
						System.err.println("error parsing size attribute in attribute " + name);
						return;
					}
				}

				ZclAttributeDescr zclAttributeDescriptor = new ZclAttributeDescr(id, name, type, size, access, defValue, mandatory,
						factor, "", reportable);

				if (insideServerCommands)
					zclClusterDescriptor.addServerAttributeDescriptor(zclAttributeDescriptor);
				else
					zclClusterDescriptor.addClientAttributeDescriptor(zclAttributeDescriptor);

				zclAttributeDescriptor.isReportable(reportable);

			} else if (tag == "client") {
				// client commands begins
				insideServerCommands = false;
			} else if (tag == "server") {
				insideServerCommands = true;
			} else if (tag.equals("command")) {
				int id = Converter.parseInteger(attrs.getNamedItem("id").getNodeValue());
				String name = attrs.getNamedItem("name").getNodeValue();
				Node mandatoryItem = attrs.getNamedItem("mandatory");
				Node manufactureCodeItem = attrs.getNamedItem("manufacturerCode");
				boolean mandatory = true;
				boolean manufacturerSpecific = false;
				short manufacturerCode = 0x00;
				byte frameType = 0x01; // cluster specific
				byte direction = 0x01; // direction server to client

				Node responseNameItem = attrs.getNamedItem("response_name");
				Node isResponseItem = attrs.getNamedItem("response");

				if (mandatoryItem != null) {
					mandatory = Converter.parseBoolean(mandatoryItem.getNodeValue());
				}

				name = transformName(name);

				if (manufactureCodeItem != null) {
					manufacturerCode = (short) Converter.parseInteger(manufactureCodeItem.getNodeValue());
					manufacturerSpecific = true;
				}

				Dictionary zclResponses;

				if (insideServerCommands) {
					zclResponses = zclResponsesServerSide;
					direction = 0x00; // client to server direction
				} else {
					zclResponses = zclResponsesClientSide;

					direction = 0x01; // server to client direction
				}

				String responseName = null;
				if (responseNameItem != null)
					responseName = responseNameItem.getNodeValue();

				zclCommandDescriptor = new ZclCommandDescriptor(id, name, frameType, manufacturerSpecific, direction,
						manufacturerCode);

				if (responseName != null) {
					zclCommandDescriptor.setResponseName(transformName(responseName));
				}

				boolean isResponse = false;

				if (isResponseItem != null)
					isResponse = Converter.parseBoolean(isResponseItem.getNodeValue());

				if (direction == 0x00)
					zclClusterDescriptor.addServerCommandDescriptor(zclCommandDescriptor);
				else
					zclClusterDescriptor.addClientCommandDescriptor(zclCommandDescriptor);

				if (isResponse) {
					zclCommandDescriptor.isResponse(true);
					zclResponses.put(zclCommandDescriptor.getName(), zclCommandDescriptor);
				}

			} else if (tag.equals("param")) {
				String name = attrs.getNamedItem("name").getNodeValue();
				String type = attrs.getNamedItem("type").getNodeValue();
				name = transformName(name);

				zclCommandDescriptor.add(new ZclField(name, type));
			} else if (tag.equals("record") || tag.equals("array")) {
				if (!this.generateRecords)
					return;

				// generate the record (shall we use the inner classes?)

			} else if (tag.equals("types")) {
				return;
			}

			NodeList children = node.getChildNodes();

			if (children != null) {
				int len = children.getLength();
				for (int i = 0; i < len; i++)
					loadXml(children.item(i));

				if (tag.equals("command")) {

				}
			}

			if (tag.equals("cluster")) {
				// resolves responses
				Vector zclServerCommandsDescriptors = zclClusterDescriptor.getZclServerCommandsDescriptors();
				Iterator it = zclServerCommandsDescriptors.iterator();
				while (it.hasNext()) {
					ZclCommandDescriptor zclServerCommandDescriptor = (ZclCommandDescriptor) it.next();
					System.out.println("Server Command Descriptor " + zclServerCommandDescriptor.getName());

					if (zclServerCommandDescriptor.getResponseName() != null) {
						// look for the response
						ZclCommandDescriptor response = (ZclCommandDescriptor) zclResponsesClientSide
								.get(zclServerCommandDescriptor.getResponseName());

						if (response != null)
							zclServerCommandDescriptor.setResponse(response);
					}
				}

				Vector zclClientCommandsDescriptors = zclClusterDescriptor.getZclClientCommandsDescriptors();
				it = zclClientCommandsDescriptors.iterator();
				while (it.hasNext()) {
					ZclCommandDescriptor zclClientCommandDescriptor = (ZclCommandDescriptor) it.next();
					if (zclClientCommandDescriptor.getResponseName() != null) {
						// look for the response
						ZclCommandDescriptor response = (ZclCommandDescriptor) zclResponsesServerSide
								.get(zclClientCommandDescriptor.getResponseName());

						if (response != null)
							zclClientCommandDescriptor.setResponse(response);
					}
				}
			}
			break;

		case Node.TEXT_NODE:
			break;
		}
	}