source: TI02-CSML/trunk/csml/csml2Moles/molesReadWrite.py @ 2468

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/csml/csml2Moles/molesReadWrite.py@2468
Revision 2468, 13.0 KB checked in by selatham, 12 years ago (diff)

added listlevel

Line 
1#Dominic Lowe, BADC  18 October 2006
2#Updated Sue Latham, various, see SVN log
3
4#import cElementTree as ET
5try: #python 2.5
6    from xml.etree import cElementTree as ET
7except ImportError:
8    try:
9        # if you've installed it yourself it comes this way
10        import cElementTree as ET
11    except ImportError:
12        # if you've egged it this is the way it comes
13        from elementtree import cElementTree as ET
14
15import sys
16
17
18#this is the NEW xml schema class
19
20class xmlSchema(object):
21    ''' this class creates a mapping of the xml schema sequences so that it can be referred to when
22    writing out a new moles document - this enables elements to be written in the order specified by the schema
23    If a particular sequence mapping can't be found then the elements will be written in whichever order python sees fit.
24    It tries various searches of the schema to pick out the sequences (which can be nested)
25    '''
26    def __init__(self, schema):
27        self.schema=schema
28        self.types={}
29        self.sequences={}
30        self.names=[]
31        self.setup()
32
33    def __isParent(self,elem):
34        #if this element is a parent of other elements (excluding annotation and documentation)
35        #then return True else return false
36        if elem[:]==[]:
37            return False
38        for child in elem[:]:
39            if child.tag == '{http://www.w3.org/2001/XMLSchema}element':
40                return True
41            elif child.tag == '{http://www.w3.org/2001/XMLSchema}complexType':
42                return True
43            elif child.tag == '{http://www.w3.org/2001/XMLSchema}simpleType':
44                return True
45            elif child.tag == '{http://www.w3.org/2001/XMLSchema}annotation':
46                pass
47            elif child.tag == '{http://www.w3.org/2001/XMLSchema}sequence':
48                return True
49            elif child.tag == '{http://www.w3.org/2001/XMLSchema}choice':
50                return True
51            elif child.tag == '{http://www.w3.org/2001/XMLSchema}complexContent':
52                return True
53            elif child.tag == '{http://www.w3.org/2001/XMLSchema}documentation':
54                pass
55            elif child.tag == '{http://www.w3.org/2001/XMLSchema}restriction':
56                return True
57            elif child.tag == '{http://www.w3.org/2001/XMLSchema}extension':
58                pass
59            elif child.tag == '{http://www.w3.org/2001/XMLSchema}attribute':
60                pass #?
61            elif child.tag == '{http://www.w3.org/2001/XMLSchema}enumeration':
62                pass #?
63       
64             #pattern
65             #attributeGroup
66             #minLength
67             #minInclusive
68             #maxInclusive
69
70        return False
71       
72       
73       
74       
75    def __checkChildren(self, parentclassname, elem):     
76        #if parentclassname == 'dgMetadataProvenance':
77            #pdb.set_trace()
78        for child in elem[:]:
79            childname = None
80            if child.attrib.has_key('name'):       
81                if child.attrib['name'][-4:]=='Type':
82                    if child.attrib['name'] in ['dgDataSetType','dgFeatureType']:  #add other rogue 'names' ending in Type to this list
83                        childname=child.attrib['name']
84                    else:
85                        childname=child.attrib['name'][:-4]
86                else:
87                    childname=child.attrib['name']
88                if child.attrib.has_key('type'):
89                    if child.attrib['type'][:6]=='moles:':
90                        typename=child.attrib['type'][6:-4]
91                        self.types[childname]=typename             
92            elif child.attrib.has_key('ref'):
93                if child.attrib['ref'][:6]=='moles:':
94                    childname=child.attrib['ref'][6:]
95            if childname is not None:
96                if self.sequences[parentclassname] is None:
97                    self.sequences[parentclassname]=[childname]
98                else:
99                    tmp= self.sequences[parentclassname]                   
100                    tmp.append(childname)
101                    self.sequences[parentclassname]=tmp             
102                if self.__isParent(child):
103                    if not self.sequences.has_key(childname):
104                        self.sequences[childname]=[]
105                    self.__checkChildren(childname,child)
106            else:
107                if self.__isParent(child):
108                    self.__checkChildren(parentclassname,child)
109
110    def __resolveTypes(self):
111        for ty in self.types:
112            try:
113                self.sequences[ty]=self.sequences[self.types[ty]]
114            except:
115                pass
116           
117    def setup(self):   
118        tree = ET.parse(self.schema)
119        root = tree.getroot()
120        self.sequences['dummy']=[]
121        self.__checkChildren('dummy',root)
122        self.__resolveTypes()
123        self.sequences['dummy']=None
124   
125    def lookupOrder(self, dict,classname):
126        '''takes the attributes in a dictionary and orders them according to the schema sequence'''
127        try:       
128            order=self.sequences[classname]
129        except KeyError:
130            order = []
131            for key in dict:
132                #print key error
133                print 'KEY ERROR %s'%classname
134                if key is not 'schema':
135                    if key is not 'ns':
136                         order.append(key) # if it can't be found an unordered list is returned from the original dictionary items
137            #print 'returning %s'%order
138        return order
139
140class molesElement(object):
141    ''' molesElement class - base class of all elements '''
142    def __init__(self, namespace=None, **kwargs):
143        if namespace !=None:
144            self.ns=namespace
145        else:
146            self.ns = '{http://ndg.nerc.ac.uk/moles}'
147        self.__dict__.update(kwargs)
148   
149    def __combineattributes(self,attname, newChild):
150        att = getattr(self,attname)
151        if isinstance(att,molesElement):
152            setattr(self,attname,[att, newChild])
153        else:
154            att.append(newChild)
155            setattr(self, attname,att)
156           
157    def _stripNS(self, tagtostrip):
158        try:
159            elemname=tagtostrip.split('}')[1]
160            ns=tagtostrip.split('}')[0]+'}'
161        except IndexError:
162            elemname=tagtostrip
163            ns='{https://ndg.nerc.ac.uk/moles}'
164        return elemname, ns
165           
166        ns=tagtostrip.split('}')[1]
167     
168   
169    def addChildElem(self, childname, childobj):
170        #sometimes you want to add a child element but don't know if there is one already. In which case you want to create a list of child objects.
171        if hasattr(self, childname):
172            currentattribute=getattr(self,childname)
173            if type(getattr(self,childname)) is list:
174                currentattribute.append(childobj)
175            else:
176                newlist=[currentattribute]
177                newlist.append(childobj)
178                setattr(self,childname, newlist)
179        else:
180            setattr(self,childname, childobj)
181   
182    def toXML(self,molesFrag, schema=None):
183        if schema != None:
184            self.schema=schema
185        else:
186            self.schema=None
187        #print molesFrag.tag
188        orderedAttribs=schema.lookupOrder(self.__dict__,molesFrag.tag)
189        for item in orderedAttribs:
190           #print "item in orderedAttribs is %s" %item
191           if type(item) is xmlSchema:
192                        continue
193           if item == '{http://ndg.nerc.ac.uk/moles}':
194                continue
195           if hasattr(self, item):
196                if isinstance(self.__dict__[item], molesElement):
197                    frag=ET.Element(item)
198                    self.__dict__[item].toXML(frag,schema=self.schema)
199                    molesFrag.append(frag)
200                elif isinstance(self.__dict__[item], list):
201                    for it in self.__dict__[item]:
202                        if isinstance(it, molesElement):
203                            frag=ET.Element(item)
204                            it.toXML(frag, schema=self.schema)
205                            molesFrag.append(frag)
206                        else:
207                            frag=ET.Element(item)
208                            frag.text=it                           
209                            molesFrag.append(frag)
210                else:
211                    frag=ET.Element(item)
212                    frag.text=self.__dict__[item]
213                    molesFrag.append(frag)
214        return molesFrag
215           
216    def fromXML(self,molesFrag):
217        children = molesFrag.getchildren()
218       
219        if children ==[]:
220            elementWithoutNS, ns=self._stripNS(molesElement.tag)
221            setattr(self,elementWithoutNS, molesElement.text)
222        if children!=[]:
223            for child in children:
224                if child.getchildren()!=[]:
225                    childWithoutNS, ns=self._stripNS(child.tag)
226                    newClass=type(childWithoutNS, (molesElement,),{})
227                    newChild=newClass(ns)
228                    newChild.fromXML(child)
229                    kw=child.tag
230                    if hasattr(self, childWithoutNS):
231                        self.__combineattributes(childWithoutNS, newChild)
232                    else:
233                        setattr(self,childWithoutNS, newChild)
234                else:
235                    childWithoutNS, ns=self._stripNS(child.tag)
236                    setattr(self,childWithoutNS, child.text)
237       
238                   
239class dgMetadata(molesElement):   
240    def __init__(self, **kwargs):
241        molesElement.__init__(self, **kwargs)
242       
243    def toXML(self):
244        self.schema = xmlSchema('ndgmetadata1.3.xsd')
245        molesFrag=ET.Element('dgMetadata')
246        molesFrag.attrib['xmlns']='http://ndg.nerc.ac.uk/moles'
247        molesElement.toXML(self,molesFrag,schema=self.schema)
248        return molesFrag
249
250
251class MolesDoc(object):
252    def __init__(self):
253        self._createClasses()
254   
255    def _create_a_class(self,name, base_class):
256        aNewClass=type(name, (base_class,),{})
257        return aNewClass
258
259    def _createClasses(self):
260        #if you want more classes just add their names to this list
261        #could probably examine the schema here....
262        classList= \
263        ['dataModelID', \
264        'dgDataGranule', \
265        'dgDataEntity', \
266        'dgMetadataRecord', \
267        'dgMetadataID',
268        'dgCoverage', \
269        'dgDataCoverage',\
270        'dgSpatioTemporalRange',\
271        'dgSpatioTemporalCoverage', \
272        'dgSpatialCoverage', \
273        'dgTemporalCoverage', \
274        'dgBoundingBox', \
275        'dgArea',\
276        'DateRange', \
277        'dgDataSummary', \
278        'dgParameterSummary', \
279        'dgParameterValue', \
280        'dgValueDataParameter', \
281        'dgStandardUnit', \
282        'dgOriginalUnit', \
283        'dgRangeDataParameter', \
284        'dgEnumerationParameter', \
285        'dgParameterGroup', \
286        'dgComponentParameter', \
287        'dgStdParameterMeasured', \
288        'dgStandardUnit', \
289        'dgValidTermID', \
290        'dgValidTermParentID', \
291        'dgValidSubterm', \
292        'ListLevel',\
293        'metadataDescriptionID', \
294        'dgMetadataDescription', \
295        'dgStructuredKeyword', \
296        'abstract',\
297        'descriptionSection',\
298        'dgReferenceClass',\
299        'descriptionOnlineReference',\
300        'dgSimpleLink',\
301        'logos',\
302        'logoURI',\
303        'dgDataSetType',\
304        'dgSimulation',\
305        'dgAnalysis',\
306        'dgMeasurement',\
307        'dgFeatureType',\
308        'dgDataRoles',\
309        'dgDataCreator',\
310        'dgDataCurator',\
311        'dgRoleHolder',\
312        'dgOrganisationID',\
313        'dgPersonID',\
314        'dgRoleID',\
315        'contactDetails',\
316        'address',\
317        'dgActivity',\
318        'relatedActivity',\
319        'dgActivityDataCollection',\
320        'dgActivityDataProject',\
321        'dgActivityDataCampaign',\
322        'dgActivityDataInvestigation',\
323        'dgActivityRole',\
324        'dgActivityDeployment',\
325        'dgActivityCoverage',\
326        'dgActivityDuration',\
327        'ActivityDeployment',\
328        'DateStart',\
329        'DateEnd',\
330        'ActivityID',\
331        'DataProductionToolID',\
332        'ObservationStationID',\
333        'ObsStationDeployment',\
334        'dgPrincipalInvestigator',\
335        'dgInvestigator',\
336        'dgFlight',\
337        'dgCruise',\
338        'RelatedDeployment',\
339        'dgModel',\
340        'DPTDeployment',\
341        'dgInstrument',\
342        'dgDataProductionTool',\
343        'dgDPTRole',\
344        'dgObservationStation',\
345        'dgStationaryPlatform',\
346        'dgMovingPlatform',\
347        'dgLandStation',\
348        'dgMooring',\
349        'position',\
350        'dgStationGroup',\
351        'dgShip',\
352        'vesselType',\
353        ]
354
355        for className in classList:
356            newClass=self._create_a_class(className, molesElement)
357            setattr(self,className,newClass)
358
359
360def main():
361    schema = xmlSchema('ndgmetadata1.3.xsd') 
362       
363    #print schema.sequences
364    for key in schema.sequences:
365        print '------------------------------------------------------------------'
366        print key
367        print schema.sequences[key]
368
369
370 
371
372if __name__=='__main__':
373    main()
Note: See TracBrowser for help on using the repository browser.