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

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

added classes. Put some things to ignore.

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
7class xmlSchema(object):
8    ''' this class creates a mapping of the xml schema sequences so that it can be referred to when
9    writing out a new moles document - this enables elements to be written in the order specified by the schema
10    If a particular sequence mapping can't be found then the elements will be written in whichever order python sees fit.
11    It tries various searches of the schema to pick out the sequences (which can be nested)
12    '''
13    def __init__(self, schema):
14        self.sequences={}
15        def __addSequence(molesname, sequence):
16            '''adds a new sequences to the list, also handles xs:choice'''
17            seqlist=[]
18            for elem in sequence[:]:
19                if elem.attrib.has_key('name'):
20                    seqlist.append(elem.attrib['name'])
21                if elem.attrib.has_key('ref'):
22                    seqlist.append(elem.attrib['ref'].split(':')[1])
23                if elem.tag == '{http://www.w3.org/2001/XMLSchema}choice':
24                    for subelem in elem[:]:
25                        if subelem.attrib.has_key('name'):
26                            seqlist.append(subelem.attrib['name'])
27            self.sequences[molesname]=seqlist
28
29        for event, elem in ET.iterparse(schema):
30            '''look for sequences in complexTypes'''
31            if elem.tag == '{http://www.w3.org/2001/XMLSchema}complexType':
32                if elem.attrib.has_key('name'):
33                    molesclassname= elem.attrib['name']
34                    if elem.attrib['name'][-4:]=='Type':
35                        molesclassname=molesclassname[:-4]
36                    for subelem in elem[:]:
37                        if subelem.tag=='{http://www.w3.org/2001/XMLSchema}sequence':
38                            __addSequence(molesclassname,subelem)
39                            for subsubelem in subelem[:]:
40                                if subsubelem.tag=='{http://www.w3.org/2001/XMLSchema}sequence':
41                                    __addSequence(molesclassname,subsubelem)
42            if elem.tag == '{http://www.w3.org/2001/XMLSchema}element':
43                '''Look for parents of complex types - sometimes a complexType is declared but does not have a name and
44              the name belongs to the parent 'element' element.'''
45                if elem.attrib.has_key('name'):
46                    molesclassname= elem.attrib['name']
47                    for subelem in elem[:]:
48                        if subelem.tag == '{http://www.w3.org/2001/XMLSchema}complexType':
49                            for subsubelem in subelem[:]:
50                                if subsubelem.tag=='{http://www.w3.org/2001/XMLSchema}sequence':
51                                    __addSequence(molesclassname,subsubelem)
52            '''this bit handles the use of types. If some element has a name and a type attribute then if that type is complex it has
53            the same sequence as the type e.g. <xs:element name="dataModelID" type="moles:dgMetadataIDType">
54            need to run iterparse again as this needs to be done when all elements have already been parsed. '''
55            for event, elem in ET.iterparse(schema):
56                if elem.tag == '{http://www.w3.org/2001/XMLSchema}element':
57                    if elem.attrib.has_key('name'):
58                        molesclassname= elem.attrib['name']
59                        if elem.attrib.has_key('type'):
60                            typename=elem.attrib['type']
61                            if typename[-4:]=='Type':
62                                 typename=typename[:-4].split(':')[1]  #may also be prefixed by moles
63                            try:
64                                seq=self.sequences[typename]
65                                self.sequences[molesclassname]=seq
66                            except KeyError:
67                                pass  #can't find anything
68       
69           
70    def lookupOrder(self, dict,classname):
71        '''takes the attributes in a dictionary and orders them according to the schema sequence'''
72        try:
73            order=self.sequences[classname]
74            #print classname
75            #print order
76        except KeyError:
77            #print 'keyerror %s!'%classname
78            order = []
79            for key in dict:
80                order.append(dict[key]) # if it can't be found an unordered list is returned from the original dictionary items
81        return order
82
83class molesElement(object):
84    ''' molesElement class - base class of all elements '''
85    def __init__(self, namespace=None, **kwargs):
86        if namespace !=None:
87            self.ns=namespace
88        else:
89            self.ns = '{http://ndg.nerc.ac.uk/moles}'
90        self.__dict__.update(kwargs)
91   
92    def __combineattributes(self,attname, newChild):
93        att = getattr(self,attname)
94        if isinstance(att,molesElement):
95            setattr(self,attname,[att, newChild])
96        else:
97            att.append(newChild)
98            setattr(self, attname,att)
99           
100    def _stripNS(self, tagtostrip):
101        try:
102            elemname=tagtostrip.split('}')[1]
103            ns=tagtostrip.split('}')[0]+'}'
104        except IndexError:
105            elemname=tagtostrip
106            ns='{https://ndg.nerc.ac.uk/moles}'
107        return elemname, ns
108           
109        ns=tagtostrip.split('}')[1]
110     
111   
112    def addChildElem(self, childname, childobj):
113        #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.
114        if hasattr(self, childname):
115            currentattribute=getattr(self,childname)
116            if type(getattr(self,childname)) is list:
117                currentattribute.append(childobj)
118            else:
119                newlist=[currentattribute]
120                newlist.append(childobj)
121                setattr(self,childname, newlist)
122        else:
123            setattr(self,childname, childobj)
124   
125    def toXML(self,molesFrag, schema=None):
126        if schema != None:
127            self.schema=schema
128        else:
129            self.schema=None
130        orderedAttribs=schema.lookupOrder(self.__dict__,molesFrag.tag)
131        for item in orderedAttribs:
132           #print "item in orderedAttribs is %s" %item
133           if type(item) is xmlSchema:
134                        continue
135           if item == '{http://ndg.nerc.ac.uk/moles}':
136                continue
137           if hasattr(self, item):
138                if isinstance(self.__dict__[item], molesElement):
139                    frag=ET.Element(item)
140                    self.__dict__[item].toXML(frag,schema=self.schema)
141                    molesFrag.append(frag)
142                elif isinstance(self.__dict__[item], list):
143                    for it in self.__dict__[item]:
144                        if isinstance(it, molesElement):
145                            frag=ET.Element(item)
146                            it.toXML(frag, schema=self.schema)
147                            molesFrag.append(frag)
148                        else:
149                            frag=ET.Element(item)
150                            frag.text=it
151                else:
152                    frag=ET.Element(item)
153                    frag.text=self.__dict__[item]
154                    molesFrag.append(frag)
155        return molesFrag
156           
157    def fromXML(self,molesFrag):
158        children = molesFrag.getchildren()
159       
160        if children ==[]:
161            elementWithoutNS, ns=self._stripNS(molesElement.tag)
162            setattr(self,elementWithoutNS, molesElement.text)
163        if children!=[]:
164            for child in children:
165                if child.getchildren()!=[]:
166                    childWithoutNS, ns=self._stripNS(child.tag)
167                    newClass=type(childWithoutNS, (molesElement,),{})
168                    newChild=newClass(ns)
169                    newChild.fromXML(child)
170                    kw=child.tag
171                    if hasattr(self, childWithoutNS):
172                        self.__combineattributes(childWithoutNS, newChild)
173                    else:
174                        setattr(self,childWithoutNS, newChild)
175                else:
176                    childWithoutNS, ns=self._stripNS(child.tag)
177                    setattr(self,childWithoutNS, child.text)
178       
179                   
180class dgMetadata(molesElement):   
181    def __init__(self, **kwargs):
182        molesElement.__init__(self, **kwargs)
183       
184    def toXML(self):
185        self.schema = xmlSchema('ndgmetadata1.3.xsd')
186        molesFrag=ET.Element('dgMetadata')
187        molesFrag.attrib['xmlns']='http://ndg.nerc.ac.uk/moles'
188        molesElement.toXML(self,molesFrag,schema=self.schema)
189        return molesFrag
190
191
192class MolesDoc(object):
193    def __init__(self):
194        self._createClasses()
195   
196    def _create_a_class(self,name, base_class):
197        aNewClass=type(name, (base_class,),{})
198        return aNewClass
199
200    def _createClasses(self):
201        #if you want more classes just add their names to this list
202        #could probably examine the schema here....
203        classList= \
204        ['dataModelID', \
205        'dgDataGranule', \
206        'dgDataEntity', \
207        'dgMetadataRecord', \
208        'dgMetadataID',
209        'dgCoverage', \
210        'dgDataCoverage',\
211        'dgSpatioTemporalCoverage', \
212        'dgSpatialCoverage', \
213        'dgTemporalCoverage', \
214        'dgBoundingBox', \
215        'DateRange', \
216        'dgDataSummary', \
217        'dgParameterSummary', \
218        'dgParameterValue', \
219        'dgValueDataParameter', \
220        'dgStandardUnit', \
221        'dgOriginalUnit', \
222        'dgRangeDataParameter', \
223        'dgEnumerationParameter', \
224        'dgParameterGroup', \
225        'dgComponentParameter', \
226        'dgStdParameterMeasured', \
227        'dgStandardUnit', \
228        'dgValidTermID', \
229        'dgValidTermParentID', \
230        'dgValidSubterm', \
231        'metadataDescriptionID', \
232        'dgMetadataDescription', \
233        'dgStructuredKeyword', \
234        ]
235
236        for className in classList:
237            newClass=self._create_a_class(className, molesElement)
238            setattr(self,className,newClass)
Note: See TracBrowser for help on using the repository browser.