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

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

Fixed molesreadwrite to allow multiple simple elements - eg addresslines

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