1   
  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  @bug: WHY IS THE IMO message screwing up the day field? 
 23  @license: GPL v2 
 24  ''' 
 25   
 26  import sys 
 27  from lxml import etree  
 28   
 30      ''' 
 31      Return the position number of the child node.  It seems like this 
 32      really should be a part of the element tree interface.  Perhaps 
 33      I overlooked it. 
 34      ''' 
 35      for i in range(len(parent)): 
 36          if parent[i]==child: return i 
 37      return None 
  38   
 39   
 41      ''' 
 42      Replace each include-struct with the structure.  This code is not 
 43      pretty, but it seems to work.  The include-struct name is 
 44      prepended to each field name within the struct.  The 
 45      include-struct description is also added to before the fields 
 46      description. 
 47   
 48      @param inET: lxml element tree to expand 
 49      @return: lxml element tree with expanded structures 
 50      ''' 
 51      inET.xinclude() 
 52      import copy 
 53      outET = copy.deepcopy(inET) 
 54       
 55   
 56      root = outET.getroot() 
 57      includeStructs = root.xpath('message/include-struct') 
 58      for inc in includeStructs: 
 59   
 60          if verbose: print 'inc:',inc.attrib['name'], 'parent:',inc.getparent().tag 
 61          parent = inc.getparent() 
 62          nodePosition = getPos(parent,inc) 
 63           
 64   
 65          structName = inc.attrib['struct'] 
 66          baseName = inc.attrib['name']+'_' 
 67   
 68          if len(inc.xpath('do_not_mangle_name'))>0: 
 69              if verbose: print 'Not mangling',structName,baseName[:-1] 
 70              baseName = '' 
 71           
 72   
 73           
 74          structDef = root.xpath("//struct[@name='"+structName+"']") 
 75   
 76           
 77          inc.getparent().replace(inc,etree.Comment('Struct include of '+inc.attrib['name']+' was here')) 
 78   
 79          replacement=copy.deepcopy(structDef[0]) 
 80   
 81          postgis=False  
 82          postgisName=None 
 83          postgisType=None 
 84          if 'postgis_type' in replacement.attrib: 
 85              postgis=True 
 86              postgisType=replacement.attrib['postgis_type'] 
 87              postgisName=inc.attrib['name']  
 88              if verbose: print 'Found PostGIS datatype for structure:',postgisName,postgisType 
 89               
 90   
 91           
 92   
 93          for subfield in replacement.xpath('field'): 
 94              subfield.attrib['name']=baseName+subfield.attrib['name'] 
 95              desc = subfield.xpath('description') 
 96   
 97              if postgis: 
 98                  if verbose: print 'Annotating',subfield.attrib['name'], 'with postgis info' 
 99                  subfield.attrib['postgisType']=postgisType 
100                  subfield.attrib['postgisName']=postgisName 
101   
102              if len(desc)==1: 
103                  txt = inc.xpath('description')[0].text 
104                  if None == txt: 
105                      if verbose: 'WARNING: are you sure you want no text in this description?' 
106                      txt = '' 
107                  else: txt +='  '   
108                  desc[0].text=  txt+desc[0].text  
109              else: 
110                  print 'WARNING: no description for subfield!!!!  Must have exactly one description field' 
111               
112   
113               
114   
115              newPos = nodePosition+getPos(replacement,subfield)  
116              nodePosition+=1 
117              parent.insert(newPos,subfield) 
118           
119   
120      return outET 
 121   
123      ''' 
124      Replace each include-struct with the structure.  This code is not 
125      pretty, but it seems to work.  The include-struct name is 
126      prepended to each field name within the struct.  The 
127      include-struct description is also added to before the fields 
128      description. 
129   
130      @param inET: lxml element tree to expand 
131      @return: lxml element tree with expanded structures 
132      ''' 
133      import copy 
134      outET = copy.deepcopy(inET) 
135   
136      root = outET.getroot() 
137      structs = root.xpath('struct') 
138      for struct in structs: 
139          if verbose: print 'nuking struct:',struct.attrib['name'] 
140          struct.getparent().replace(struct,etree.Comment('Struct '+struct.attrib['name']+' was here')) 
141   
142      return outET 
 143   
144  if __name__ == '__main__': 
145      from optparse import OptionParser 
146      parser = OptionParser(usage="%prog [options]", 
147                              version="%prog "+__version__) 
148      parser.add_option('-i','--input-file',dest='inFilename',default=None, 
149                          help='AIS to read from')     
150      parser.add_option('-o','--output-file',dest='outFilename',default='out-ais.xml', 
151                          help='New AIS file that has structures expanded')     
152      parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 
153                          help='Verbose mode') 
154   
155      parser.add_option('-k','--keep-structs',dest='keepStructs',default=False,action='store_true', 
156                          help='Keep the structure definitions at the beginning of the file') 
157      (options,args) = parser.parse_args() 
158   
159      tree = etree.parse(options.inFilename) 
160       
161      newET = expandAis(tree,options.verbose) 
162      if not options.keepStructs:  
163          newET = nukeStructs(newET,options.verbose) 
164      newET.write(options.outFilename) 
165   
166       
167