def restoreSequence( molecule, sequenceFile ): """Restore sequence from sequenceFile. Return self or None on error. """ if (not os.path.exists( sequenceFile ) ): io.error('Molecule.restoreSequence: sequenceFile "{0}" not found\n', sequenceFile ) return None #end if # compatibility if molecule.content.version < 0.92: fileObject = open(sequenceFile, 'r') for line in fileObject: exec(line) #end for fileObject.close() else: sequence = xmlTools.xML2obj( sequenceFile ) if sequence is None: io.error('restoreSequence: error parsing xml-file "{0}"', sequenceFile) return None for chainId, resName, resNum, convention in sequence: molecule.addResidue( chainId, resName, resNum, convention ) #end for #end if return molecule
def restoreStereoAssignments( molecule, stereoFileName ): """ Restore the stereo assignments from xml stereoFileName, return count or -1 on error """ if not os.path.exists( stereoFileName ): return -1 stereo = xmlTools.xML2obj(stereoFileName) if stereo is None: io.error('restoreStereoAssignment: parsing xml-file "{0}"\n', stereoFileName) return -1 #end if count = 0 for nameTuple in stereo: atm = molecule.decodeNameTuple( nameTuple ) if atm is None: io.error('restoreStereoAssignment: invalid atom nameTuple ({0})', nameTuple) else: atm.stereoAssigned = True count += 1 #end if #end for #nTdebug('Molecule.restoreStereoAssignments: restored %d stereo assignments from "%s\n',count, stereoFileName) return count
def decode(string, backend=None, keys=False, referenceObject=None): """ Convert a JSON string into a Python object. The keyword argument 'keys' defaults to False. If set to True then jsonpickle will decode non-string dictionary keys into python objects via the jsonpickle protocol. referenceObject is passed as attribute to to the unpickler instance (available as 'context' attribute in custom handlers that are derived from the Basehandler class). GWV changed to return a tuple return (obj, metadata) tuple >>> str(decode('"my string"')) 'my string' >>> decode('36') 36 """ from cing.Libs.jsonTools import unpickler if backend is None: backend = json #GWV: unwrap the metadata and the object metadata,obj = unpickler.decode(string, backend=backend, keys=keys, referenceObject=referenceObject) if metadata is None: io.error('jsonTools.decode: failed to decode metadata\n') if obj is None: io.error('jsonTools.decode: failed to decode object\n') return obj, metadata
def restore(self, fromPath=None, restoreLinkages=True): """ restore validation data fromPath (set to default if None); establish linkage to project if restoreLinkages == True return True on error """ if fromPath is None: fromPath = self.project.path() / cdefs.directories.validation else: fromPath = disk.Path(fromPath) if not fromPath.exists(): io.error('ValidationData.restore: path "{0}" does not exist\n', fromPath) error = False # used to track if decoding of any of the json files generated an error for vfile in fromPath.glob('*.json'): io.debug('ValidationData.restore: restoring {0}, restoreLinkages = \n', vfile, restoreLinkages) if restoreLinkages: if self._restoreWithLinkages(vfile): error = True else: if self._restoreWithoutLinkages(vfile): error = True #end if #end for return error
def getResult(self, theObject, key, default=None): """v3:Returns validation result from theObject for key, None if not present or value set to None, unless default is defined which is then set and returned (in the spirit of dict.setdefault()) """ #io.debug('>get> {0!s} {1!s} {2!s}\n', theObject, key, default) if theObject is None: io.error('ValidationData.getResult: invalid object\n') return None if key is None: io.error('ValidationData.getResult: invalid key\n') return None #v3: use attribute method so v3 will not 'suffer' if not hasattr(theObject, ValidationResultsContainer.KEY): if default is not None: self.setResult(theObject, key, default) return default # ==None or default #end if container = getattr(theObject, ValidationResultsContainer.KEY) if key not in container: if default is not None: self.setResult(theObject, key, default) return default # ==None or default #endif result = container[key] if result is None and default is not None: self.setResult(theObject, key, default) return default # ==None or default return result # ==result
def quote(inputString): "return a single or double quoted string" single = (find(inputString, "'") >= 0) double = (find(inputString, '"') >= 0) if single and double: io.error("in quote: both single and double quotes in [{0}]\n", inputString) return None if double: return "'" + inputString + "'" return '"' + inputString + '"'
def upgrade100(project, restore): """ Do all things to upgrade project to current configuration All versions <= 1.00 """ nTmessage('*** upgrade100: upgrading %s from version %s ***', project, project.version) verbosity = cing.verbosity # make sure we get all if we heave debug on if cing.verbosity < cing.verbosityDebug: cing.verbosity = cing.verbosityWarning # Molecules for molName in project.moleculeNames: pathName = project.molecules.path(molName) mol = Molecule.open(pathName) if mol: mol.status = 'keep' project.appendMolecule(mol) #end if nTdebug('upgrade100: restored %s', mol) #end for # restore the lists for pl in [project.peaks, project.distances, project.dihedrals, project.rdcs, project.coplanars]: pl.restore() #end for # Now patch talos+ nTmessage('==> upgrade100: talosPlus') if restoreTalosPlus100(project): io.error('upgrade100: restoring talosPlus data failed\n') # Now patch queeny # nTmessage('==> upgrade100: queeny') # if restoreQueeny100(project): # nTerror('upgrade100: restoring queeny data failed') # project.saveQueeny() # # # Now patch shiftx # if restoreShiftx100(project): # nTerror('upgrade100: restoring shiftx data failed') # return None # project.saveShiftx() # Plugin registered functions nTdebug('upgrade100: calling plugins') project._callPluginRestores() # save to consolidate project.save() cing.verbosity = verbosity return Project.open(project.name, constants.PROJECT_OLD, restore=restore)
def nThandle(node): """Handle a given node, return object of None in case of Error """ if node is None: io.error("nThandle: None node\n") return None #end if if node.nodeName not in XMLhandlers: io.error('nThandle: no handler for XML <{0}>\n', node.nodeName) return None #end if return XMLhandlers[node.nodeName].handle(node)
def handleMultipleElements(self, node): 'For each child handle XML' self.printDebugNode(node) if node.nodeName != self.name: io.error('XML%Handler: invalid XML handler for node <{0}>\n', node.nodeName) return None #end if result = [] for subNode in node.childNodes: if subNode.nodeType == Node.ELEMENT_NODE: result.append(nThandle(subNode)) #end if #end for # nTdebug("==>%s %s",repr(node), result) return result
def modify(self, index, newId, type=None): """ Return new pid with position index modified by newId """ parts = self._split() idparts = parts[1:] try: # NB this allows negative indices also, according to normal Python rules idparts[index] = newId except IndexError: io.error('Pid.modify: invalid index ({0})\n', index+1) parts[1:] = idparts if type is not None: parts[0] = type return Pid.new(*parts)
def json2obj(path, referenceObject=None): """return object from serialised representation in json file or None on error """ from cing.Libs.disk import Path p = Path(str(path)) # assure path instance if not p.exists(): io.error('json2obj: path "{0}" does not exist\n', path) return None, None with open(p,'r') as fp: try: obj, keyedMetadata = decode(fp.read(), referenceObject=referenceObject) except ValueError: io.error('json2obj: trying to decode object from "{0}" failed\n', path) return None, None return obj, keyedMetadata
def decodePid(sourceObject, thePid): """ try to decode thePid relative to sourceObject return decoded pid object or None on not found or Error """ if thePid is None: return None # assure a Pid object if not isinstance(thePid, Pid): if hasattr(thePid, 'asPid'): # we probably did get passed an object thePid = thePid.asPid else: # just try it as a string thePid = Pid(str(thePid)) #end if #end if if not thePid.isValid: io.error('decodePid: pid "{0}" is invalid', thePid) return None #end if # check if thePid describes the source object if hasattr(sourceObject,'asPid'): if sourceObject.asPid == thePid: return sourceObject #end if # apparently not, let try to traverse down to find the elements of thePid obj = sourceObject for p in thePid: #print( 'decodePid>>', p, object) if p not in obj: return None obj = obj[p] #end for # found an object, check if it is the right kind if thePid.type != obj.__class__.__name__: io.error('decodePid: type "{0}" does not match object type "{1}"', thePid.type, obj.__class__.__name__) return None return obj
def xML2obj(path=None, string=None): """Convert XML file to object returns object or None on error """ if path == None and string==None: io.error("xML2obj: no input defined\n") return None # nTdebug("Starting to read XML from path: " + repr(path)+ " or string: " + repr(string)) if path: doc = minidom.parse(path) else: doc = minidom.parseString(string) # nTdebug("Done reading XML") root = doc.documentElement result = nThandle(root) doc.unlink() return result
def restoreTalosPlus100(project): """ Restore talos+ results by parsing files. Return True on error """ if project is None: io.error("restoreTalosPlus100: No project defined\n") return True if project.molecule is None: return True # Gracefully returns talosDefs = project.getStatusDict('talosPlus') if not talosDefs.completed: io.error('restoreTalosPlus100: talosPlus not completed\n') return True return project.parseTalosPlus()
def openMol_075( path ) : """Static method to restore molecule from directory path implements the <=0.75 storage model returns Molecule instance or None on error """ # old format content = xmlTools.xML2obj( path=os.path.join( path, NTmolParameters.contentFile ) ) if not content: io.error('openMol_075: error reading xml file "{0}"\n', os.path.join( path, NTmolParameters.contentFile ) ) return None #end if content.keysformat() io.debug('openMol_075: content from xml-file: %s', content.format()) mol = molecule.Molecule( name = content.name ) if not mol: io.error('openMol_075: initializing molecule\n') return None #end if mol.content = content if content.has_key('sequenceFile') and \ restoreSequence(mol, os.path.join(path, content.sequenceFile)) is None: return None if content.has_key('resonanceFile') and \ restoreResonances(mol, os.path.join(path, content.resonanceFile), append=False) < 0: return None if content.has_key('stereoFile') and \ restoreStereoAssignments(mol, os.path.join(path, content.stereoFile)) < 0: return None if content.has_key('coordinateFile') and \ restoreCoordinates(mol, os.path.join(path, content.coordinateFile), append=False) is None: return None mol._check() mol.updateAll() return mol
def openMol_094(path) : """Static method to restore molecule from SML file path: 0.75< version <= 0.90 returns Molecule instance or None on error """ #print '*** Opening using Molecule.openMol_094' if (not os.path.exists( path )): io.error('Molecule.open: smlFile "{0}" not found\n', path) return None #end if mol = Molecule.SMLhandler.fromFile(path) # pylint: disable=E1101 if not mol: io.error('openMol_094: open from "{0}" failed\n', path) return None #end if mol._check() mol.updateAll() return mol
def execute(self, cutoff = 0.1): """Do the steps for a full analysis """ if self.project is None: io.error('Queeny.execute: undefined project') return True if self.molecule is None: io.error('Queeny.execute: undefined molecule') return True self.reset() # do the topology self.initTopology() self.triangulateAll( cutoff=cutoff, maxDepth = 4 ) self.setUncertainty(constants.QUEENY_UNCERTAINTY1_STR) # do the restraints self.initRestraints() self.triangulateAll( cutoff=cutoff, maxDepth = 3 ) self.setUncertainty(constants.QUEENY_UNCERTAINTY2_STR) # calculate the information content for each atom, residue self.setInformation(constants.QUEENY_UNCERTAINTY1_STR, constants.QUEENY_UNCERTAINTY2_STR, constants.QUEENY_INFORMATION_STR) return False
def setResult(self, theObject, key, result): """v3: Add result to theObject's validation container instance under key, add reverse linkage to result under constants.OBJECT_KEY add container to self return True on error """ #io.debug('>set> {0!s} {1!s} {2!s}\n', theObject, key, result) if theObject is None: io.error('ValidationData.setResult: invalid object\n') return True if key is None: io.error('ValidationData.setResult: invalid key\n') return True #v3: use attribute method so v3 will not 'suffer' # check if theObject has a validation container, create one if needed if not hasattr(theObject, ValidationResultsContainer.KEY): container = ValidationResultsContainer() # add this container self.addContainer(theObject, container) # setattr(theObject, ValidationResultsContainer.KEY, container) # container.setattrOnly(constants.OBJECT_KEY, theObject) else: container = getattr(theObject, ValidationResultsContainer.KEY) #end if # add the result and set the object's reference # conditionally adjust the the pid of result instance container[key] = result if result is not None: result[constants.OBJECT_KEY] = theObject if hasattr(theObject,'asPid'): result.setPid(theObject.asPid.id, ValidationResultsContainer.KEY, key ) #end if #end if return False
def _restoreWithLinkages(self, vfile): """ restore validation results in vfile, reestablish linkages to project objects """ vdata, metadeta = jsonTools.json2obj(vfile, self.project) if vdata is None: io.error('ValidationData._restoreWithLinkages: unable to restore objects from "{0}"\n', vfile) return True #end if for result in vdata: #print 'ValidationData.restore> ', result obj = self.project.getByPid(result[constants.OBJECT_KEY]) if obj is None: io.error('ValidationData._restoreWithLinkages: unable to decode pid "{0} (file {1})"\n', result[constants.OBJECT_KEY], vfile ) return True #end if self.project.validationData.setResult(obj, result.KEY, result) #end for return False
def _restoreWithoutLinkages(self, vfile): """ restore validation results in vfile, do not decode pid's into linkages Add containers to self.data when needed """ # everything is maintained as pid's vdata, metadeta = jsonTools.json2obj(vfile) if vdata is None: io.error('ValidationData._restoreWithoutLinkages: unable to restore objects from "{0}"\n', vfile) return True for result in vdata: # check for the presence of appropriate container objPid = result[constants.OBJECT_KEY] if objPid in self.data: container = self.data[objPid] else: container = ValidationResultsContainer() self.data[objPid] = container #end if container[result.KEY] = result
def parseTalosPlus( project, tmp=None ): """Import talosPlus results. Return True on error. """ if project is None: io.warning("parseTalosPlus: No project defined\n") return False if project.molecule is None: io.warning("parseTalosPlus: No molecule defined\n") return False talosDefs = project.getStatusDict(constants.TALOSPLUS_KEY, **talosDefaults) if not talosDefs.completed: io.warning("parseTalosPlus: No talos+ was run\n") return False path = project.validationPath(talosDefs.directory) if not path: io.error('parseTalosPlus: directory "{0}" with talosPlus data not found\n', path) return True if _findTalosOutputFiles(path, talosDefs): return True predFile = path / talosDefs.predFile if not predFile.exists() or predFile.isdir(): io.error('parseTalosPlus: file "{0}" with talosPlus predictions not found\n', predFile) return True predSSFile = path / talosDefs.predSSFile if not predSSFile.exists() or predSSFile.isdir(): io.error('parseTalosPlus: file "{0}" with talosPlus SS predictions not found\n', predSSFile) return True _resetTalosPlus(project) if _importTalosPlus(project, predFile, predSSFile): return True talosDefs.parsed = True if talosPlus2restraints(project): io.error("parseTalosPlus: Failed talosPlus2restraints\n") return True return False
def restoreResonances( molecule, fileName, append = True ): """Restore resonances from fileName Optionally append to existing settings Return resonanceCount or -1 on error """ if not os.path.exists( fileName ): io.error('restoreResonances: file "{0}" not found\n', fileName ) return -1 #end if if not append: molecule.initResonances() #end if #execfile( fileName ) # 25 Sep 2007: Explicit coding, less memory, better: file = open(fileName, 'r') for line in file: exec(line) #end for file.close() resonanceCount = len(molecule.resonanceSources) #nTdebug('Molecule.restoreResonances: %s (%d)', fileName, resonanceCount) return resonanceCount
def restoreCoordinates( molecule, fileName, append = True ): """Restore coordinates from fileName Optionally append to existing settings Return self or None on error """ if not os.path.exists( fileName ): io.error('restoreCoordinates: file "{0}" not found\n', fileName ) return None #end if if not append: for atm in molecule.allAtoms(): atm.coordinates = ntu.NTlist() #end for #end if #execfile(fileName); # 25 Sep 2007: Explicit coding, less memory, better: file = open(fileName, 'r') for line in file: exec(line) #end for file.close() #nTdebug('Molecule.restoreCoordinates: %s (%d)', fileName, self.modelCount) return molecule #end def
def obj2XML(obj, stream=None, path=None): """Convert an object to XML output to stream or path gwv 13 Jun08: return object or None on error """ if obj is None: io.error("obj2XML: no object\n") return None if stream is None and path is None: io.error("obj2XML: no output defined\n") return None closeFile = 0 if not stream: stream = open(path, 'w') closeFile = 1 fprintf(stream, '<?xml version="1.0" encoding="ISO-8859-1"?>\n') nTtoXML(obj, depth=0, stream=stream, indent=' ') if closeFile: stream.close() return obj
def handleSingleElement(self, node): """Returns single element below node from DOM tree""" self.printDebugNode(node) if node.nodeName != self.name: io.error('XML%sHandler: invalid XML handler for node <{0}>\n', node.nodeName) return None #end if if len(node.childNodes) != 1: io.error("XML%sHandler: malformed DOM tree ({0})\n", self.name) return None #end if if node.childNodes[0].nodeType != Node.TEXT_NODE: io.error("XML%sHandler: malformed DOM tree ({0}), expected TEXT_NODE containing value\n", self.name) return None #end if result = node.childNodes[0].nodeValue # nTdebug("==>%s %s",repr(node), result) return result
def upgrade075(project, restore): """ Upgrade project from 075 or earlier conventions return upgraded project or None on error """ io.message('upgrade075: converting from CING version {0}\n', project.version) # 0.75 version had moleculeNames stored in molecules attribute # >=0.76 version molecules is a ProjectList instance project.moleculeNames = project.molecules # store the project file and reopen to have correct settings project._save2json() pr = classes.Project._restoreFromJson(project.path(cing.cingPaths.project)) if pr == None: io.error('upgrade075: conversion from version %s failed on read\n', project.version) return None for molName in pr.moleculeNames: pathName = pr.path(cing.directories.molecules, molName) # old reference, versions 0.48-0.75 if pr.version <= 0.48: pathName = pr.path('Molecules', molName) # old reference # end if io.debug('upgrade075: trying molecule conversion from {0}\n', pathName) if not pathName.exists(): io.error('upgrade075: old molecule pathName "{0}" does not exist\n', pathName) return None mol = openMol_075(pathName) if not mol: io.error('upgrade075: conversion from version {0} failed on molecule {1}\n', project.version, molName) return None pathName.removedir() # Save molecule to new format mol.save(pr.molecules.path(molName)) #end for # restore pr.restore() # Save to consolidate pr.save() return cing.Legacy.Legacy100.upgrade100.upgrade100(pr, restore)
from cing.Libs.NTutils import NTsort from cing.Libs.NTutils import nTerror from cing.Libs.NTutils import nTtracebackError from cing.Libs.NTutils import nTwarning from cing.Libs.NTutils import nTmessage from cing.Libs.NTutils import nTdebug from cing.Libs.NTutils import nTfill from cing.Libs.NTutils import nTzap from cing.Libs.NTutils import Odict from cing.Libs.io import sprintf try: import pyximport except ImportError: io.error('Importing pyximport routines for queeny\n') raise ImportError pyximport.install() try: import cing.Libs.cython.superpose as superpose except ImportError: io.error('Importing cython routines for queeny\n') raise ImportError # versions < 0.95 not logged with version number # cing versions >1.0 first ones to include this __version__ = cing.__version__ # defaults for the queeny status dict
def _parseShiftxOutput(fileName, project, chainId): """ Parse shiftx generated output (gv_version!). Store result in shiftx attribute (which is a NTlist type) of each atom format file: # Entries marked with a * may have inaccurate shift predictions. # Entries marked with a value < -600 should be ignored 501 H N 116.3173 501 H CA 55.4902 501 H CB 29.9950 501 H C 169.8446 501 H H 8.4401 or in 1y4o: 1 G N 109.7404 1 G CA 45.2787 or in 1afp 10 K HZ3 3.7795 # A HZ3 that might not be present. Return True on error; eg. when the file is absent. """ if not os.path.exists(fileName): nTerror("_parseShiftxOutput: Failed to find %s" % fileName) return True if project is None: nTerror("_parseShiftxOutput: no project defined") return True molecule = project.molecule nTdebug("_parseShiftxOutput: parsing %s", fileName) atomDict = molecule.getAtomDict(constants.IUPAC, chainId) for line in AwkLike(fileName, commentString="#", minNF=4): shift = line.float(4) if shift != -666.000: lineCol1 = int(line.dollar[1].strip("*")) atmName = line.dollar[3] if chainId is not None: atm = molecule.decodeNameTuple((constants.IUPAC, chainId, lineCol1, atmName)) # happens for all N-terminal H because the Nterminal residue has H1/2/3 # fix: if atm is None and atmName == "H": atm = molecule.decodeNameTuple((constants.IUPAC, chainId, lineCol1, "H1")) else: atm = None if atomDict.has_key((lineCol1, atmName)): atm = atomDict[(lineCol1, atmName)] # end if # print '>>', atm if not atm: pass nTdebug("parseShiftxOutput: chainId [%s] line %d (%s)", chainId, line.NR, line.dollar[0]) # happens for all LYS without HZ3. else: result = project.validationData.getResult(atm, constants.SHIFTX_KEY, ShiftxResult()) if result is None: io.error("_parseShiftxOutput: retrieving ShiftxResult for atom {0}\n", atm) else: result.DATA.append(shift) # LEGACY: atm.shiftx.append(shift)
def nTtoXML(obj, depth=0, stream=sys.stdout, indent='\t', lineEnd='\n'): """Generate XML: check for method toXML or standard types int, float, tuple, list, dict """ if (obj == None): nTindent(depth, stream, indent) fprintf(stream, "<None/>") fprintf(stream, lineEnd) elif hasattr(obj, 'toXML'): obj.toXML(depth, stream, indent, lineEnd) elif (type(obj) == int): nTindent(depth, stream, indent) fprintf(stream, "<int>%s</int>", repr(obj)) fprintf(stream, lineEnd) elif (type(obj) == bool): nTindent(depth, stream, indent) fprintf(stream, "<bool>%s</bool>", repr(obj)) fprintf(stream, lineEnd) elif (type(obj) == float): nTindent(depth, stream, indent) fprintf(stream, "<float>%s</float>", repr(obj)) fprintf(stream, lineEnd) elif (type(obj) == str): nTindent(depth, stream, indent) # fprintf( stream, "<string>%s</string>", saxutils.escape( obj ) ) fprintf(stream, "<string>%s</string>", unicode(saxutils.escape(obj))) fprintf(stream, lineEnd) elif (type(obj) == unicode): nTindent(depth, stream, indent) fprintf(stream, "<unicode>%s</unicode>", unicode(saxutils.escape(obj))) fprintf(stream, lineEnd) elif (type(obj) == list): nTindent(depth, stream, indent) fprintf(stream, "<list>") fprintf(stream, lineEnd) for a in obj: nTtoXML(a, depth+1, stream, indent, lineEnd) #end for nTindent(depth, stream, indent) fprintf(stream, "</list>") fprintf(stream, lineEnd) elif (type(obj) == tuple): nTindent(depth, stream, indent) fprintf(stream, "<tuple>") fprintf(stream, lineEnd) for a in list(obj): nTtoXML(a, depth+1, stream, indent, lineEnd) #end for nTindent(depth, stream, indent) fprintf(stream, "</tuple>") fprintf(stream, lineEnd) elif (type(obj) == dict): nTindent(depth, stream, indent) fprintf(stream, "<dict>") fprintf(stream, lineEnd) for key, value in obj.iteritems(): nTindent(depth+1, stream, indent) fprintf(stream, "<key name=%s>", quote(key)) fprintf(stream, lineEnd) nTtoXML(value, depth+2, stream, indent, lineEnd) nTindent(depth+1, stream, indent) fprintf(stream, "</key>") fprintf(stream, lineEnd) #end for nTindent(depth, stream, indent) fprintf(stream, "</dict>") fprintf(stream, lineEnd) else: pass io.error('nTtoXML: undefined object "{0}": cannot generate XML\n', obj) # reenable when done testing.
def handleDictElements(self, node): 'For dictionary elements return another dictionary.' self.printDebugNode(node) if node.nodeName != self.name: io.error('XML%sHandler: invalid XML handler for node <{0}>\n', node.nodeName) return None #end if result = {} # We have two dict formats # original 'NT' format: ## ##<dict> ## <key name="noot"> ## <int>2</int> ## </key> ## <key name="mies"> ## <int>3</int> ## </key> ## <key name="aap"> ## <int>1</int> ## </key> ##</dict> ## # Or Apple plist dict's ##<dict> ## <key>Key</key> ## <string>3F344E56-C8C2-4A1C-B6C7-CD84EAA1E70A</string> ## <key>Title</key> ## <string>New on palm</string> ## <key>Type</key> ## <string>com.apple.ical.sources.naivereadwrite</string> ##</dict> # first collect all element nodes, skipping the 'empty' text nodes subNodes = [] for n in node.childNodes: # print '>>',n if n.nodeType == Node.ELEMENT_NODE: subNodes.append(n) #end for if len(subNodes) == 0: return result #append all keys, checking for 'format' as outlined above i = 0 while (i < len(subNodes)): #print '>>', len(subNodes), i, str(subNodes[i]), 'childnodes:', len(subNodes[i].childNodes), str(subNodes[i].childNodes[0]) self.printDebugNode(subNodes[i]) try: keyName = subNodes[i].attributes.get('name').nodeValue #test for valid childNodes; have seen cases they don't exits (!?) if len(subNodes[i].childNodes) > 1: value = nThandle(subNodes[i].childNodes[1]) else: #nTdebug('XMLhandler.handleDictElements: empty key "%s", value set to None', keyName) value = None i += 1 except AttributeError: keyName = subNodes[i].childNodes[0].nodeValue value = nThandle(subNodes[i+1]) i += 2 # print ">>", keyName, value result[keyName] = value #end while # nTdebug("==>%s %s",repr(node), result) return result