Package ais :: Module expandais
[hide private]
[frames] | no frames]

Source Code for Module ais.expandais

  1  #!/usr/bin/env python 
  2   
  3  __version__ = '$Revision: 4820 $'.split()[1] 
  4  __date__ = '$Date: 2006-09-28 12:11:51 -0400 (Thu, 28 Sep 2006) $'.split()[1] 
  5  __author__ = 'Kurt Schwehr' 
  6   
  7  __doc__=''' 
  8  Expand structs in ais xml to include-struct elements while applying name mangling 
  9   
 10  @requires: U{lxml<http://codespeak.net/lxml/>} 
 11  @requires: U{epydoc<http://epydoc.sourceforge.net/>} > 3.0alpha3 
 12   
 13  @author: '''+__author__+''' 
 14  @version: ''' + __version__ +''' 
 15  @copyright: 2006 
 16  @var __date__: Date of last svn commit 
 17  @undocumented: __version__ __author__ __doc__ parser 
 18  @since: 2006-Sep-26 
 19  @status: under development 
 20  @organization: U{CCOM<http://ccom.unh.edu/>} 
 21   
 22  @license: GPL v2 
 23  ''' 
 24   
 25  import sys 
 26  from lxml import etree  
 27   
28 -def getPos(parent,child):
29 ''' 30 Return the position number of the child node. It seems like this 31 really should be a part of the element tree interface. Perhaps 32 I overlooked it. 33 ''' 34 for i in range(len(parent)): 35 if parent[i]==child: return i 36 return None
37 38
39 -def expandAis(inET,verbose=False):
40 ''' 41 Replace each include-struct with the structure. This code is not 42 pretty, but it seems to work. The include-struct name is 43 prepended to each field name within the struct. The 44 include-struct description is also added to before the fields 45 description. 46 47 @param inET: lxml element tree to expand 48 @return: lxml element tree with expanded structures 49 ''' 50 inET.xinclude() 51 import copy 52 outET = copy.deepcopy(inET) 53 #outET.xinclude() 54 55 root = outET.getroot() 56 includeStructs = root.xpath('message/include-struct') 57 for inc in includeStructs: 58 59 if verbose: print 'inc:',inc.attrib['name'], 'parent:',inc.getparent().tag 60 parent = inc.getparent() 61 nodePosition = getPos(parent,inc) 62 #if verbose: print 'pos:',nodePosition 63 64 structName = inc.attrib['struct'] 65 baseName = inc.attrib['name']+'_' 66 #if verbose: print 'baseName:',baseName, 'structName=',structName 67 68 # // means find all struct tags at all levels 69 structDef = root.xpath("//struct[@name='"+structName+"']") 70 71 # Put in a comment where the include-struct was. 72 inc.getparent().replace(inc,etree.Comment('Struct include of '+inc.attrib['name']+' was here')) 73 74 replacement=copy.deepcopy(structDef[0]) 75 76 postgis=False # Does this structure have an associated postgis data structure? 77 postgisName=None 78 postgisType=None 79 if 'postgis_type' in replacement.attrib: 80 postgis=True 81 postgisType=replacement.attrib['postgis_type'] 82 postgisName=inc.attrib['name'] #baseName 83 if verbose: print 'Found PostGIS datatype for structure:',postgisName,postgisType 84 85 86 # FIX: what happens when the include is at the beginning or end of the list? 87 88 for subfield in replacement.xpath('field'): 89 subfield.attrib['name']=baseName+subfield.attrib['name'] 90 desc = subfield.xpath('description') 91 92 if postgis: 93 if verbose: print 'Annotating',subfield.attrib['name'], 'with postgis info' 94 subfield.attrib['postgisType']=postgisType 95 subfield.attrib['postgisName']=postgisName 96 97 if len(desc)==1: 98 desc[0].text= inc.xpath('description')[0].text +'\n\n'+ desc[0].text 99 else: 100 print 'WARNING: no description for subfield!!!! Must have exactly one description field' 101 # Now that the node is ready, jam it in there after the replaced comment 102 103 #print "FIX: make sure these end up in the right place!!!!" 104 105 newPos = nodePosition+getPos(replacement,subfield) #+1 106 nodePosition+=1 107 parent.insert(newPos,subfield) 108 #if verbose: print 'New parent:',etree.tostring(parent) 109 110 return outET
111
112 -def nukeStructs(inET,verbose=False):
113 ''' 114 Replace each include-struct with the structure. This code is not 115 pretty, but it seems to work. The include-struct name is 116 prepended to each field name within the struct. The 117 include-struct description is also added to before the fields 118 description. 119 120 @param inET: lxml element tree to expand 121 @return: lxml element tree with expanded structures 122 ''' 123 import copy 124 outET = copy.deepcopy(inET) 125 126 root = outET.getroot() 127 structs = root.xpath('struct') 128 for struct in structs: 129 if verbose: print 'nuking struct:',struct.attrib['name'] 130 struct.getparent().replace(struct,etree.Comment('Struct '+struct.attrib['name']+' was here')) 131 132 return outET
133 134 if __name__ == '__main__': 135 from optparse import OptionParser 136 parser = OptionParser(usage="%prog [options]", 137 version="%prog "+__version__) 138 parser.add_option('-i','--input-file',dest='inFilename',default=None, 139 help='AIS to read from') 140 parser.add_option('-o','--output-file',dest='outFilename',default='out-ais.xml', 141 help='New AIS file that has structures expanded') 142 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 143 help='Verbose mode') 144 145 parser.add_option('-k','--keep-structs',dest='keepStructs',default=False,action='store_true', 146 help='Keep the structure definitions at the beginning of the file') 147 (options,args) = parser.parse_args() 148 149 tree = etree.parse(options.inFilename) 150 #tree.xinclude() 151 newET = expandAis(tree,options.verbose) 152 if not options.keepStructs: 153 newET = nukeStructs(newET,options.verbose) 154 newET.write(options.outFilename) 155 156 #if options.verbose: print etree.tostring(newET) 157