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

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

removing print statements

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           if hasattr(self, item):
133                if isinstance(self.__dict__[item], molesElement):
134                    frag=ET.Element(item)
135                    self.__dict__[item].toXML(frag,schema=self.schema)
136                    molesFrag.append(frag)
137                elif isinstance(self.__dict__[item], list):
138                    for it in self.__dict__[item]:
139                        if isinstance(it, molesElement):
140                            frag=ET.Element(item)
141                            it.toXML(frag, schema=self.schema)
142                            molesFrag.append(frag)
143                        else:
144                            frag=ET.Element(item)
145                            frag.text=it
146                else:
147                    frag=ET.Element(item)
148                    frag.text=self.__dict__[item]
149                    molesFrag.append(frag)
150        return molesFrag
151           
152    def fromXML(self,molesFrag):
153        children = molesFrag.getchildren()
154       
155        if children ==[]:
156            elementWithoutNS, ns=self._stripNS(molesElement.tag)
157            setattr(self,elementWithoutNS, molesElement.text)
158        if children!=[]:
159            for child in children:
160                if child.getchildren()!=[]:
161                    childWithoutNS, ns=self._stripNS(child.tag)
162                    newClass=type(childWithoutNS, (molesElement,),{})
163                    newChild=newClass(ns)
164                    newChild.fromXML(child)
165                    kw=child.tag
166                    if hasattr(self, childWithoutNS):
167                        self.__combineattributes(childWithoutNS, newChild)
168                    else:
169                        setattr(self,childWithoutNS, newChild)
170                else:
171                    childWithoutNS, ns=self._stripNS(child.tag)
172                    setattr(self,childWithoutNS, child.text)
173       
174                   
175class dgMetadata(molesElement):   
176    def __init__(self, **kwargs):
177        molesElement.__init__(self, **kwargs)
178       
179    def toXML(self):
180        self.schema = xmlSchema('ndgmetadata1.3.xsd')
181        molesFrag=ET.Element('dgMetadata')
182        molesFrag.attrib['xmlns']='http://ndg.nerc.ac.uk/moles'
183        molesElement.toXML(self,molesFrag,schema=self.schema)
184        return molesFrag
185
186
187class MolesDoc(object):
188    def __init__(self):
189        self._createClasses()
190   
191    def _create_a_class(self,name, base_class):
192        aNewClass=type(name, (base_class,),{})
193        return aNewClass
194
195    def _createClasses(self):
196        #if you want more classes just add their names to this list
197        #could probably examine the schema here....
198        classList= \
199        ['dataModelID', \
200        'dgDataGranule', \
201        'dgDataEntity', \
202        'dgMetadataRecord', \
203        'dgMetadataID',
204        'dgCoverage', \
205        'dgDataCoverage',\
206        'dgSpatioTemporalCoverage', \
207        'dgSpatialCoverage', \
208        'dgTemporalCoverage', \
209        'dgBoundingBox', \
210        'DateRange', \
211        'dgDataSummary',\
212        'dgParameterSummary',\
213        'dgRangeDataParameter',\
214        'dgStdParameterMeasured',\
215        'dgStandardUnit',\
216        'dgValidTermID',\
217        'metadataDescriptionID',\
218        'dgMetadataDescription', \
219        'dgStructuredKeyword', \
220        ]
221
222
223        for className in classList:
224            newClass=self._create_a_class(className, molesElement)
225            setattr(self,className,newClass)
Note: See TracBrowser for help on using the repository browser.