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__ myparser
18 @since: 2006-Sep-26
19 @status: under development
20 @organization: U{CCOM<http://ccom.unh.edu/>}
21
22
23 @license: Restricted while in development to NOAA and USCG.
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 import copy
52 outET = copy.deepcopy(inET)
53
54 root = outET.getroot()
55 includeStructs = root.xpath('message/include-struct')
56 for inc in includeStructs:
57
58 if verbose: print 'inc:',inc.attrib['name'], 'parent:',inc.getparent().tag
59 parent = inc.getparent()
60 nodePosition = getPos(parent,inc)
61
62
63 structName = inc.attrib['struct']
64 baseName = inc.attrib['name']+'_'
65
66
67 structDef = root.xpath("struct[@name='"+structName+"']")
68
69
70 inc.getparent().replace(inc,etree.Comment('Struct include of '+inc.attrib['name']+' was here'))
71
72 replacement=copy.deepcopy(structDef[0])
73
74
75 for subfield in replacement.xpath('field'):
76 subfield.attrib['name']=baseName+subfield.attrib['name']
77 desc = subfield.xpath('description')
78 if len(desc)==1:
79 desc[0].text= inc.xpath('description')[0].text +'\n\n'+ desc[0].text
80 else:
81 print 'WARNING: no description for subfield!!!! Must have exactly one description field'
82
83 newPos = nodePosition+getPos(replacement,subfield)+1
84 nodePosition+=1
85 parent.insert(newPos,subfield)
86
87
88 return outET
89
91 '''
92 Replace each include-struct with the structure. This code is not
93 pretty, but it seems to work. The include-struct name is
94 prepended to each field name within the struct. The
95 include-struct description is also added to before the fields
96 description.
97
98 @param inET: lxml element tree to expand
99 @return: lxml element tree with expanded structures
100 '''
101 import copy
102 outET = copy.deepcopy(inET)
103
104 root = outET.getroot()
105 structs = root.xpath('struct')
106 for struct in structs:
107 if verbose: print 'nuking struct:',struct.attrib['name']
108 struct.getparent().replace(struct,etree.Comment('Struct '+struct.attrib['name']+' was here'))
109
110 return outET
111
112 if __name__ == '__main__':
113 from optparse import OptionParser
114 myparser = OptionParser(usage="%prog [options]",
115 version="%prog "+__version__)
116 myparser.add_option('-i','--input-file',dest='inFilename',default=None,
117 help='AIS to read from')
118 myparser.add_option('-o','--output-file',dest='outFilename',default='out-ais.xml',
119 help='New AIS file that has structures expanded')
120 myparser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
121 help='Verbose mode')
122
123 myparser.add_option('-k','--keep-structs',dest='keepStructs',default=False,action='store_true',
124 help='Keep the structure definitions at the beginning of the file')
125 (options,args) = myparser.parse_args()
126
127 newET = expandAis(etree.parse(options.inFilename),options.verbose)
128 if not options.keepStructs:
129 newET = nukeStructs(newET,options.verbose)
130 newET.write(options.outFilename)
131
132
133