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

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

Fix bugs in DPTGenerator:

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