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