etisserant@171: #!/usr/bin/env python etisserant@171: # -*- coding: utf-8 -*- etisserant@171: etisserant@171: #This file is part of CanFestival, a library implementing CanOpen Stack. etisserant@171: # etisserant@171: #Copyright (C): Edouard TISSERANT, Francis DUPIN and Laurent BESSARD etisserant@171: # etisserant@171: #See COPYING file for copyrights details. etisserant@171: # etisserant@171: #This library is free software; you can redistribute it and/or etisserant@171: #modify it under the terms of the GNU Lesser General Public etisserant@171: #License as published by the Free Software Foundation; either etisserant@171: #version 2.1 of the License, or (at your option) any later version. etisserant@171: # etisserant@171: #This library is distributed in the hope that it will be useful, etisserant@171: #but WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@171: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU etisserant@171: #Lesser General Public License for more details. etisserant@171: # etisserant@171: #You should have received a copy of the GNU Lesser General Public etisserant@171: #License along with this library; if not, write to the Free Software etisserant@171: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA etisserant@171: etisserant@171: from xml.parsers import expat etisserant@171: etisserant@171: import node etisserant@171: from node import * etisserant@171: etisserant@171: maxObjects = 8 etisserant@171: etisserant@171: currentPDOIndex = 0 etisserant@171: currentBitsMapped = 0 etisserant@171: currentMaxObjects = 0 etisserant@171: currentNbMappedObjects = 0 etisserant@171: etisserant@171: nextPdoIndex = {"rx":0x1400,"tx":0x1800} etisserant@171: etisserant@171: valid_elements = ["node","heartbeat_consumers","sdo_clients","pdo","mapped_object", etisserant@171: "pdo_param","pdo_receive","pdo_transmit","mapped_variable","mapped_table", etisserant@171: "mapped_string_variable","mapped_string_table"] etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Callback method of parse etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def StartElement(name, attrs): etisserant@171: if name in valid_elements: etisserant@171: if name == "node": etisserant@171: startNode(attrs) etisserant@171: elif name == "heartbeat_consumers": etisserant@171: startHeartBeatConsumers(attrs) etisserant@171: elif name == "sdo_clients": etisserant@171: startSdoClients(attrs) etisserant@171: elif name in ["pdo_param","pdo_receive","pdo_transmit"]: etisserant@171: raise ValueError, """!!! The XML grammar has changed. etisserant@171: Please, open your xml file, delete the tags pdo_param, pdo_receive and pdo_transmit. etisserant@171: Use instead the tag pdo for each pdo to create, and (optional) use the tag mapped_object (menu pdo/map and object ...).""" etisserant@171: elif name == "pdo": etisserant@171: startPdo(attrs) etisserant@171: elif name == "mapped_object": etisserant@171: startMappedObject(attrs) etisserant@171: elif name == "mapped_variable": etisserant@171: startMappedVariable(attrs) etisserant@171: elif name == "mapped_table": etisserant@171: startMappedTable(attrs) etisserant@171: elif name == "mapped_string_variable": etisserant@171: startMappedVariable(attrs) etisserant@171: elif name == "mapped_string_table": etisserant@171: startMappedTable(attrs) etisserant@171: etisserant@171: def EndElement(name): etisserant@171: if name in valid_elements: etisserant@171: if name == "node": etisserant@171: stopNode() etisserant@171: etisserant@171: def CharacterData(data): etisserant@171: pass etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Creation of Node etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def startNode(attrs): etisserant@171: name = attrs["name"] etisserant@171: Node.SetNodeName(name) etisserant@171: etisserant@171: if "node_id" in attrs and len(attrs["node_id"]) > 0: etisserant@171: node_id = eval(attrs["node_id"]) etisserant@171: else: etisserant@171: node_id = 0x01 # We define here a default node_id. etisserant@171: Node.SetNodeID(node_id) etisserant@171: etisserant@171: typeNode = attrs["type_node"] etisserant@171: Node.SetNodeType(typeNode) etisserant@171: etisserant@171: if "device_type_1000" in attrs: etisserant@171: device_type = eval(attrs["device_type_1000"]) etisserant@171: else: etisserant@171: device_type = 0 etisserant@171: Node.AddEntry(0x1000, 0, device_type) etisserant@171: Node.AddEntry(0x1001, 0, 0) etisserant@171: Node.AddEntry(0x1005, 0, 0x00000080) etisserant@171: Node.AddEntry(0x1006, 0, 0) etisserant@171: Node.AddEntry(0x1007, 0, 0) etisserant@171: etisserant@171: if "manufacturer_device_name_1008" in attrs: etisserant@171: manufacturer_device_name = attrs["manufacturer_device_name_1008"] etisserant@171: else: etisserant@171: manufacturer_device_name = "" etisserant@171: Node.AddEntry(0x1008, 0, manufacturer_device_name) etisserant@171: etisserant@171: if "manufacturer_hardware_version_1009" in attrs: etisserant@171: manufacturer_hardware_version = attrs["manufacturer_hardware_version_1009"] etisserant@171: else: etisserant@171: manufacturer_hardware_version = "__DATE__" etisserant@171: Node.AddEntry(0x1009, 0, manufacturer_hardware_version) etisserant@171: etisserant@171: if "manufacturer_software_version_100A" in attrs: etisserant@171: manufacturer_software_version = attrs["manufacturer_software_version_100A"] etisserant@171: else: etisserant@171: manufacturer_software_version = 0 etisserant@171: Node.AddEntry(0x100A, 0, manufacturer_software_version) etisserant@171: etisserant@171: if "vendor_id_1018" in attrs: etisserant@171: vendor_id = eval(attrs["vendor_id_1018"]) etisserant@171: else: etisserant@171: vendor_id = 0 etisserant@171: if "product_code_1018" in attrs: etisserant@171: product_code = eval(attrs["product_code_1018"]) etisserant@171: else: etisserant@171: product_code = 0 etisserant@171: if "revision_number_1018" in attrs: etisserant@171: revision_number = eval(attrs["revision_number_1018"]) etisserant@171: else: etisserant@171: revision_number = 0 etisserant@171: if "serial_number_1018" in attrs: etisserant@171: serial_number = eval(attrs["serial_number_1018"]) etisserant@171: else: etisserant@171: serial_number = 0 etisserant@171: Node.AddEntry(0x1018, 1, vendor_id) etisserant@171: Node.AddEntry(0x1018, 2, product_code) etisserant@171: Node.AddEntry(0x1018, 3, revision_number) etisserant@171: Node.AddEntry(0x1018, 4, serial_number) etisserant@171: etisserant@171: def stopNode(): etisserant@171: heartBeatProducer() etisserant@171: sdoServer() etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Creation of PDO in Object Dictionary etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def startPdo(attrs): etisserant@171: global currentPdoIndex etisserant@171: global currentMaxObjects etisserant@171: global currentNbMappedObjects etisserant@171: global currentBitsMapped etisserant@171: global maxObjects etisserant@171: etisserant@171: cobId = 0 etisserant@171: transmissionType = 253 # Default is on request. Why not ? etisserant@171: etisserant@171: # Find the type of the PDO and search the index of the last added etisserant@171: type = attrs["type_rx_tx"] etisserant@171: index = nextPdoIndex[type] etisserant@171: etisserant@171: # If the index of the PDO is define, verify that it has a good index etisserant@171: if "index_communication_parameter" in attrs: etisserant@171: index = eval(attrs["index_communication_parameter"]) etisserant@171: if type == "rx" and not 0x1400 <= index <= 0x15FF: etisserant@171: raise ValueError, """!!! Abort because Index PDO receive : 0x%04X not valid. etisserant@171: Valid index is 0x1400 ... 0x15FF"""%index etisserant@171: if type == "tx" and not 0x1800 <= index <= 0x19FF: etisserant@171: raise ValueError, """!!! Abort because Index PDO transmit : 0x%04X not valid. etisserant@171: Valid index is 0x1800 ... 0x19FF"""%index etisserant@171: etisserant@171: # Extract the PDO communication parameters etisserant@171: if "cob_id" == attrs: etisserant@171: cobId = eval(attrs["cob_id"]) etisserant@171: if "max_objects_in_pdo" == attrs: etisserant@171: maxObjects = eval(attrs["max_objects_in_pdo"]) etisserant@171: if "transmission_type" in attrs: etisserant@171: transmissionType = eval(attrs["transmission_type"]) etisserant@171: etisserant@171: if Node.IsEntry(index): etisserant@171: raise ValueError, """!!! Abort because the PDO at index : 0x%04X have been already defined."""%index etisserant@171: etisserant@171: # Communication parameters etisserant@171: Node.AddEntry(index, 1, cobId) etisserant@171: Node.AddEntry(index, 2, transmissionType) etisserant@171: etisserant@171: # Mapping parameters etisserant@171: mapping_index = index + 0x200 etisserant@171: for i in xrange(1, maxObjects + 1): etisserant@171: Node.AddEntry(mapping_index, i, 0x0) etisserant@171: etisserant@171: currentPdoIndex = index etisserant@171: currentMaxObjects = maxObjects etisserant@171: currentBitsMapped = 0 etisserant@171: currentNbMappedObjects = 0 etisserant@171: etisserant@171: nextPdoIndex[type] = index + 1 etisserant@171: etisserant@171: def startMappedObject(attrs): etisserant@171: global currentPdoIndex etisserant@171: global currentMaxObjects etisserant@171: global currentNbMappedObjects etisserant@171: global currentBitsMapped etisserant@171: etisserant@171: index = currentPdoIndex etisserant@171: mapping_index = index + 0x200 etisserant@171: etisserant@171: indexObject = eval(attrs["index"]) etisserant@171: subIndexObject = eval(attrs["sub_index"]) etisserant@171: sizeInBitsObject = eval(attrs["size_in_bits"]) etisserant@171: etisserant@171: if currentMaxObjects == 0: etisserant@171: raise ValueError, """!!! Abort because of a bogue for mapped object (defined at index 0x%04X, subIndex 0x%025X) etisserant@171: in PDO. index : 0x%04X is undefined."""%(indexObject,subindexObject,mapping_index) etisserant@171: if currentNbMappedObjects >= currentMaxObjects: etisserant@171: raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X) etisserant@171: in PDO index 0x%04X. max objects (%d) reached."""%(IndexObject,subIndexObject,mapping_index,pdo[mapping_index]["maxObjects"]) etisserant@171: if currentBitsMapped + sizeInBitsObject > 64: etisserant@171: raise ValueError, """!!! Abort mapping object (defined at index 0x%04X, subIndex 0x%02X) etisserant@171: in PDO index 0x%04X. No room to put %d bits in the PDO."""%(IndexObject,subIndexObject,mapping_index,sizeInBitsObject) etisserant@171: etisserant@171: value = eval("0x%04X%02X%02X"%(indexObject,subIndexObject,sizeInBitsObject)) etisserant@171: Node.SetEntry(mapping_index, currentNbMappedObjects + 1, value) etisserant@171: etisserant@171: currentNbMappedObjects += 1 etisserant@171: currentBitsMapped += sizeInBitsObject etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Creation of mapped variable and table etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def startMappedVariable(attrs): etisserant@171: name = attrs["name"] etisserant@171: index = eval(attrs["index"]) etisserant@171: subIndex = eval(attrs["sub_index"]) etisserant@171: etisserant@171: if "size_in_bits" in attrs: etisserant@171: size = eval(attrs["size_in_bits"]) # Numeric variable etisserant@171: if "type" in attrs: etisserant@171: type = attrs["type"] etisserant@171: if (type == "UNS"): etisserant@171: type = "UNSIGNED" etisserant@171: else: # Default type etisserant@171: type = "UNSIGNED" etisserant@171: typename = "%s%d"%(type,size) etisserant@171: etisserant@171: type_index = Manager.GetTypeIndex(typename, False) etisserant@171: if type_index == None: etisserant@171: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unrecognized type : %s"""%(name,index,subIndex,typename) etisserant@171: etisserant@171: # Begin ValueRange support etisserant@171: if "min_value" in attrs or "max_value" in attrs: etisserant@171: if "min_value" in attrs and "max_value" in attrs: etisserant@171: minValue = eval(attrs["min_value"]) etisserant@171: maxValue = eval(attrs["max_value"]) etisserant@171: if (minValue > maxValue): etisserant@171: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : error in value-range : min > max"""%(name,index,subIndex) etisserant@171: else: etisserant@171: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : You have defined only a min or a max value. \nIf you define one, you must define both."""%(name,index,subIndex) etisserant@171: etisserant@171: type_index = findRangeType(type_index, minValue, maxValue) etisserant@171: if type_index == None: etisserant@171: raise ValueError, """!!! Sorry, too many different value range have been defined""" etisserant@171: # End ValueRange support etisserant@171: etisserant@171: if "size_in_byte" in attrs: etisserant@171: size = eval(attrs["size_in_byte"]) # String variable etisserant@171: type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size) etisserant@171: if type_index == None: etisserant@171: raise ValueError, """!!! Sorry, too many different string length have been defined""" etisserant@171: etisserant@171: if "access" in attrs: etisserant@171: access = attrs["access"].lower() etisserant@171: else: etisserant@171: access = "rw" # default value etisserant@171: etisserant@171: if index < 0x2000 or index > 0xBFFF: etisserant@171: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Variable can't be defined using this index-subindex."""%(name,index,subIndex) etisserant@171: etisserant@171: if subIndex == 0: etisserant@171: Node.AddMappingEntry(index, name = name, struct = 1) etisserant@171: elif subIndex == 1: etisserant@171: Node.AddMappingEntry(index, struct = 3) etisserant@171: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: result = Node.AddMappingEntry(index, subIndex, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True}) etisserant@171: etisserant@171: if result: etisserant@171: Node.AddEntry(index, subIndex, 0) etisserant@171: else: etisserant@171: raise ValueError, """!!! ERROR : For variable "%s" at index 0x%04X, subindex 0x%02X : Unable to map"""%(name,index,subIndex) etisserant@171: etisserant@171: def startMappedTable(attrs): etisserant@171: name = attrs["name"] etisserant@171: number_elements = eval(attrs["number_elements"]) etisserant@171: index = eval(attrs["index"]) etisserant@171: etisserant@171: if "size_in_bits" in attrs: etisserant@171: size = eval(attrs["size_in_bits"]) # Numeric variable etisserant@171: if "type" in attrs: etisserant@171: type = attrs["type"] etisserant@171: if (type == "UNS"): etisserant@171: type = "UNSIGNED" etisserant@171: else: # Default type etisserant@171: type = "UNSIGNED" etisserant@171: typename = "%s%d"%(type,size) etisserant@171: etisserant@171: type_index = Manager.GetTypeIndex(typename, False) etisserant@171: if type_index == None: etisserant@171: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unrecognized type : %s"""%(name,index,typename) etisserant@171: etisserant@171: # Begin ValueRange support etisserant@171: if "min_value" in attrs or "max_value" in attrs: etisserant@171: if "min_value" in attrs and "max_value" in attrs: etisserant@171: minValue = eval(attrs["min_value"]) etisserant@171: maxValue = eval(attrs["max_value"]) etisserant@171: if (minValue > maxValue): etisserant@171: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : error in value-range : min > max"""%(name,index) etisserant@171: else: etisserant@171: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : You have defined only a min or a max value. \nIf you define one, you must define both."""%(name,index) etisserant@171: etisserant@171: type_index = findRangeType(type_index, minValue, maxValue) etisserant@171: if type_index == None: etisserant@171: raise ValueError, """!!! Sorry, too many different value range have been defined""" etisserant@171: # End ValueRange support etisserant@171: etisserant@171: if "size_in_byte" in attrs: etisserant@171: size = eval(attrs["size_in_byte"]) # String variable etisserant@171: type_index = findStringType(Manager.GetTypeIndex("VISIBLE_STRING", False), size) etisserant@171: if type_index == None: etisserant@171: raise ValueError, """!!! Sorry, too many different string length have been defined""" etisserant@171: etisserant@171: if "access" in attrs: etisserant@171: access = attrs["access"].lower() etisserant@171: else: etisserant@171: access = "rw" # default value etisserant@171: etisserant@171: if index < 0x2000 or index > 0xBFFF: etisserant@171: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Variable can't be defined using this index-subindex."""%(name,index) etisserant@171: etisserant@171: result = Node.AddMappingEntry(index, name = name, struct = 7) etisserant@171: if not result: etisserant@171: raise ValueError, """!!! ERROR : For table \"%s\" at index 0x%04X : Unable to map because a variable or a table is using this index"""%(name,index) etisserant@171: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddMappingEntry(index, 1, values = {"name" : name, "type" : type_index, "access" : access, "pdo" : True, "nbmax" : number_elements}) etisserant@171: etisserant@171: for subIndex in xrange(1,number_elements+1): etisserant@171: Node.AddEntry(index, subIndex, 0) etisserant@171: etisserant@171: def findRangeType(type, minValue, maxValue): etisserant@171: index = 0xA0 etisserant@171: while index < 0x100 and Node.IsEntry(index): etisserant@171: current_type = Node.GetEntry(index, 1) etisserant@171: if current_type == type: etisserant@171: current_minValue = Node.GetEntry(index, 2) etisserant@171: current_maxValue = Node.GetEntry(index, 3) etisserant@171: if current_minValue == minValue and current_maxValue == maxValue: etisserant@171: return index etisserant@171: index += 1 etisserant@171: if index < 0x100: etisserant@171: infos = Manager.GetEntryInfos(type, False) etisserant@171: name = "%s[%d-%d]"%(infos["name"], minValue, maxValue) etisserant@171: Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"]) etisserant@171: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddEntry(index, 1, type) etisserant@171: Node.AddEntry(index, 2, minValue) etisserant@171: Node.AddEntry(index, 3, maxValue) etisserant@171: return index etisserant@171: return None etisserant@171: etisserant@171: def findStringType(type, length): etisserant@171: index = 0xA0 etisserant@171: while index < 0x100 and Node.IsEntry(index): etisserant@171: current_type = Node.GetEntry(index, 1) etisserant@171: if current_type == type: etisserant@171: current_length = Node.GetEntry(index, 2) etisserant@171: if current_length == length: etisserant@171: return index etisserant@171: index += 1 etisserant@171: if index < 0x100: etisserant@171: infos = Manager.GetEntryInfos(type, False) etisserant@171: name = "%s%d"%(Manager.GetTypeName(type), length) etisserant@171: Node.AddMappingEntry(index, name = name, struct = 3, size = infos["size"], default = infos["default"]) etisserant@171: Node.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False}) etisserant@171: Node.AddEntry(index, 1, type) etisserant@171: Node.AddEntry(index, 2, length) etisserant@171: return index etisserant@171: return None etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Creation HeartBeat Producer & Consumers etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def heartBeatProducer(): etisserant@171: Node.AddEntry(0x1017, 0, 0) etisserant@171: etisserant@171: def startHeartBeatConsumers(attrs): etisserant@171: nombre = eval(attrs["nombre"]) etisserant@171: for i in xrange(nombre): etisserant@171: Node.AddEntry(0x1016, i + 1, 0) etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Creation of SDO Server & Clients etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def sdoServer(): etisserant@171: Node.AddEntry(0x1200, 1, 0x600 + Node.GetNodeID()) etisserant@171: Node.AddEntry(0x1200, 2, 0x580 + Node.GetNodeID()) etisserant@171: etisserant@171: def startSdoClients(attrs): etisserant@171: nombre = eval(attrs["nombre"]) etisserant@171: for i in xrange(nombre): etisserant@171: Node.AddEntry(0x1280 + i, 1, 0x600) etisserant@171: Node.AddEntry(0x1280 + i, 2, 0x580) etisserant@171: Node.AddEntry(0x1280 + i, 3, 0) etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Parse file with Saxe etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: def ParseFile(filepath): etisserant@171: return dict([( # Dict containing whole Eds etisserant@171: blocktuple[0], # EntryName : Assignements dict etisserant@171: dict([assignment.split('=') # Name : Value etisserant@171: for assignment in # Assignements are etisserant@171: blocktuple[-1].splitlines() # all the lines etisserant@171: if assignment.find('=') > 0 ] # that contains '=' etisserant@171: )) for blocktuple in [ # Split the eds files into etisserant@171: block.split("]") # (EntryName,Assignements) tuple etisserant@171: for block in # for each blocks staring with '[' etisserant@171: open(filepath,'r').read().split("[")] etisserant@171: if blocktuple[0].isalnum()]) # if EntryName exists etisserant@171: etisserant@171: def GenerateNode(filepath, manager): etisserant@171: global Node etisserant@171: global Manager etisserant@171: Manager = manager etisserant@171: Node = node.Node() etisserant@171: eds_dict = ParseFile(filepath) etisserant@171: ProfileNb=int(eds_dict["1000"]["DefaultValue"],16) & 0x0000ffff etisserant@171: if ProfileNb not in [301, 302]: etisserant@171: execfile("config/DS-%d.prf"%ProfileNb) etisserant@171: Node.SetProfileName("DS-%d"%ProfileNb) etisserant@171: Node.SetProfile(Mapping) etisserant@171: Node.SetSpecificMenu(AddMenuEntries) etisserant@171: for Entry in ParseFile(filepath): etisserant@171: pass etisserant@171: etisserant@171: return Node etisserant@171: etisserant@171: #------------------------------------------------------------------------------- etisserant@171: # Main Function etisserant@171: #------------------------------------------------------------------------------- etisserant@171: etisserant@171: if __name__ == '__main__': etisserant@171: ParseFile("test.xml") etisserant@171: